有的题还是比较有意思的
(建议做了再看~)
传送门
Start
没什么好说的,网上随便找个shellcode
exp: https://paste.ubuntu.com/p/4FXP3Drhnd/
orw
也是写shellcode,不过限制了syscall只能open, read, write,提示已经好明显了,就是先open打开文件拿到文件的fd,然后用read和fd把文件内容先读到一块地方(如.bss),最后用write把这个地方的东西打印到stdout。有一点要注意的是read和write时的长度要大一点,不然程序会crash。
网上找不到现成的,只能自己写了。。。
exp: https://paste.ubuntu.com/p/kh69RDfZ98/
(exp上面有个test是本地测试是自己弄的文件夹,因为不想在自己电脑上的home目录里建文件夹)
不过这题比较有意思的一点是限制syscall的方式。在题目的orw_seccomp函数里调用了prctl函数。
根据这里说的,prctl函数(好像是关于进程操作的函数?)通过第一个参数指定操作的类型,类型是PR_SET_SECCOMP的话会使线程进入“安全模式”(好像叫seccomp),在这种模式下syscall被限制。
calc
这题搞了一个简单而且还会算错的计算器,除了静态编译比较麻烦之外,洞其实还算好找的(吧)。calc的做法基本就是通过get_expr读算式(放到buffer里),然后通过parse_expr把运算结果(和一些中间结果)放到一个pool的结构(第一个int是记录长度,后面100个int是放数)里面。parse_expr的做法大概是遍历buffer,把数字存pool,遇到运算符的话就用一个叫eval的函数做运算。(中间有些优先级的处理没详细看 - -)
漏洞就在eval里,里面有个数组越界(underflow)的漏洞,控制一下buf的length到1的话就会变成"pool->buf[-1] += pool->buf[0]",pool->buf[-1]就是length,在这个时候是0,所以可通过 pool->buf[0]控制pool的length。
然后在parse_expr里面有有个这样的东西,count因为length被控制了所以就被控制了,count被控制了就可以往任意的地址写入num。
问题是num怎么被控制,后来发现算式如果第一个字符是运算符的话会有点问题,最终就构造了这样"+bias+value"的一个表达式,可以往(base_aderess+bias)的地址上写(value)这个值。最后写个rop就搞定了。不过还有一点要注意的是不能写0,但可以通过写1再dec来绕过。
exp: https://paste.ubuntu.com/p/pPdyCkgsXP/
3x17
题目的3x17是什么意思我到现在都搞不明白 - -。静态编译加stripped看着有点难受,把题逆完之后知道只有一个main函数,可以输入一个地址,然后往这个地址写东西(3 bytes),还有个奇怪的count。
没有信息泄漏,不知道要写什么- -,后来在@Potatso 那里听说了_fini_array这个东西,就是程序在结束前会经过一个叫_libc_csu_fini的函数,这个函数会取_fini_array里面的函数(函数指针)出来执行,然后才让程序结束。
所以通过修改_fini_array的函数就可以在main函数后多执行两个函数(因为有个v0限制),本来想如果写个main函数在_fini_array的话就可以返回main实现无数次写了,但main里面有个count限制。后来发现可以第一个函数写main,第二个函数写_libc_csu_fini的话就可以无数次进入main函数,让count溢出变回1。(有一点要注意的是_fini_array里面的函数是逆序执行的)。
所以就实现了无数次的任意位置写,于是就想写个rop,但不知道写哪里。后来发现在执行_fini_array前的rbp就是指向_fini_array(0x4b40f0)的,所以就往这里写了个"leave",然后栈被移到0x4b40e8,在0x4b40e8放个"add rsp,0x18"的rop的话,0x4b4100后面就可以放个rop chain了。后来这么做是成功了,最后的rop:
exp: https://paste.ubuntu.com/p/z43S4C7KnK/
dubblesort
实际上就是个bubble sort,输入排序数字的数量,然后输入数字,输出排序结果。
开局输个名字送libc_base:
这题利用技巧在于输入非数字的话会输入不成功,结果是用栈上的东西来排序。加上有栈溢出漏洞,就可以构造特定的ROP了。(由于有排序,会对ROP有一定要求,但是libc里面有大量的ROP,构造还是不太难的)
exp: https://paste.ubuntu.com/p/FrRw5c8R2y/
hacknote
堆的题目,思路是fastbin attack。每一条note存放了一个输出函数的指针和数据的指针(空间在栈上分配),那个输出的函数怎么看都是故意放上去的,所以很容易可以想到通过fastbin attack改变这个函数指针到system函数然后getshell。
做fastbin attack时要覆盖note块的话就数据块大小就需要跟note块大小一样(0x10,大概是12bytes以下吧),但这样会因为偶数的关系做不了fastbin attack,所以有一个trick就是中间分配一个数据块大于0x10的note隔开变成奇数(这样讲有点迷,看wp吧- -)。heap_base可以容易泄漏出来,libc_base的话可以通过把数据的指针写成.got表地址,然后打印note泄漏。
最后system函数调用时栈上的情况如下,所以第一个参数会是输出函数被覆盖成system函数的那个块的地址,这里有一个trick是可以通过构造一个“或”的表达式来绕过,如“xxxx||/bin/sh”,但这里长度只够输“sh”,虽然最后是成功了,但好像还是有点悬。
exp: https://paste.ubuntu.com/p/BXZWmmwRQT/
Silver Bullet
这题好像是一个游戏,什么鬼升级子弹然后把狼人射死?
漏洞在于power_up里的strncat函数,根据文档介绍,strncat在复制字符串后会在末尾补\x00,所以就形成了一个字节的溢出。而这里溢出的刚好把power覆盖了(power控制可以继续输入多少的description),然后就可造成更多的溢出。最后写个ROP就搞定了。(因为这里溢出的还是比较少的,所以可以先做个read来写入较长的ROP,然后leave ret到写入的ROP那里。另外,把power覆盖成很大的值可实现一键秒杀)
exp: https://paste.ubuntu.com/p/hjCJK9JqWs/
applestore
这题模拟了一个applestore(大雾),买满7174刀可以用1刀的价格换一台iphone8(而且还是强制的- -)。购物车是个双向链表,结构大概是:
漏洞点还挺明显的,就在checkout时的这个一刀换购里,送的iphone8是在栈里的,所以相当于有了一个可操控(但有些难用)的栈指针。当时找了很久到找不到在哪可以利用,后来瞄了一下别人的wp后才知道在delete的read可以覆盖这个iphone8的位置。
所以构造一下假的chunk,通过覆盖name的位置为想读信息的地址可以实现任意读(next和last写成0,不然会crash),本来打算栈地址可以通过tls得到的,但发现服务器的tls地址跟我本地的不一样...,后来才知道libc里面是放着environ的,通过environ可以得到栈的地址。
写的话可以通过delete里的unlink来写,学到了新的方法——通过unlink覆盖ebp。
exp: https://paste.ubuntu.com/p/Dz6DF6ZTk8/
Tcache Tear
给的库是2.27的,根据题目名知道应该是tcache方面的漏洞(堆题),题目逻辑挺简单的就不贴IDA了。
首先贴一下Tcache有关的教程(我认为比较全的)。
这题有个比较难搞的是"Info"那里只能输出开始时输入的"Name"位置的0x20个字符(.bss),这里可以先在填Name时制造一个0x420的fake_chunk(分配到unsorted bin的大小),通过两次free把tcache的fd指到name里,然后free掉刚制造的fake_chunk,因为要解决unlink时错误的问题,还要把free的chunk的邻近的chunk也假造一下(具体看exp)
另外制造假chunk时还要用到一个漏洞,在malloc里的输入大小是"size - 16",存在一个整数溢出,当size小于16时就可以输入任意大小了。free unsorted bin的chunk后可以通过Info泄漏libc的base。
然后本来是打算覆写atoll的got地址的,后来卡了很久才发现是"Full RELRO" - -,那就只能写malloc_hook或者free_hook了,malloc_hook的话因为one gadget条件不行就弃用了,free_hook刚好有一个符合的,然后就getshell了。
exp: https://paste.ubuntu.com/p/2GfwrZkqQw/
seethefile
我觉得他已经暗示了这是道IO_file的题目了... 可以进行几种文件操作(打开、读取、写到屏幕、关闭),最后的关闭程序时有个溢出漏洞,可以通过name的溢出覆盖文件的fp,伪造假的_IO_FILE_plus结构就可getshell (说是这么简单。。。),这题有几个放水的地方,一个是PIE是关闭的,所以bss段的地址已知,写在bss上的东西就可以直接用了;一个是程序把几个变量都放在了bss段,这样才会有上面说的溢出(好像那两东西不放bss也不行hhhh);一个是可以读处flag(做了某些过滤)以外的文件,读一下/proc/self/maps就可以拿到libc的基址。(反正就是道挺好的IO_file的练手题了)
IO_file网上也有很多教程,这里水过一下就算了(懒 - -),首先上面说了可以伪造一个_IO_FILE_plus结构体,伪造结构体主要造一下_IO_FILE_plus.vtable就行,vtable是一个(const struct _IO_jump_t)类型的结构体(据说跟C++的重载函数差不多),里面记录了一些文件操作相关的函数位址,通过覆盖/伪造里面的函数地址(比如改成system)就可以达到控制程序流的目的。然后据说vtable里面的函数的第一个参数是这个_IO_FILE本身【比如close的定义:JUMP_FIELD(_IO_close_t, __close);】,所以如果改成system的话把'/bin/sh\x00'放在伪造的结构体的头部就好了。
另外,在实践中发现在fclose中执行到【_IO_acquire_lock (fp);】这个地方程序会死掉,后来参考了yuuoniy的wp才知道要造一个假的lock (wtcl- -),然后因为lock的结构跟IO_file的差不多所以可以直接用伪造的结构体放在lock的位置(具体看ta的wp 8)。
最终造出来的_IO_FILE_plus
最终造出来的_IO_jump_t (vtable)
exp: https://paste.ubuntu.com/p/Y4nGyvx7kR/
getshell后好像因为权限问题,要通过里面提供的get_flag程序来拿flag,反正源码都给了,这里就不多说了 (逃
Death Note
Death Note好像是一部挺老的漫画了,好像是把谁的名字写到笔记上去那个人就会死掉(与题目无关hhhh)
题目已经提示了要写shellcode了,checksec发现有rwx的区域,程序的.bss和堆上都是rwx的(最终的选择是写在堆上,因为输入的name放在了堆)。代码中还有个is_printable函数(对,题目很好心的给了符号),提示要alpha_numeric的shellcode,而且长度限制80bytes以下,网上找了一堆不是长度太长就是不能用的,最后还是自己写了(顺便当练习。
写shellcode前首先要找到可以执行shellcode的地方,程序中几个操作里都有一个id的检查,说id不能超过10,但是没有检查下限,所以输入负数的话会触发underflow漏洞。
输入的id是作为note的下标,note有恰好在.bss上,所以选择适当的id就可以覆盖.got表的值,exp选择了free,因为free的参数就是某个堆块的地址,这样方便写shellcode。
接下来就是shellcode部分,alpha_numberic的shellcode写法在winesap的视频中有详细的说明,可以参照一下。这里的大概就是:首先call free时eax是堆上一个块,加0x10后就是shellcode的基址,exp存到了edi中;通过某些神奇的操作可以得到0,方法不唯一,exp存到了esi寄存器中;通过‘xor BYTE PTR [edi+0x37], al’指令可以修改shellcode的值,从而构造出'int 80'指令;通过xor的操作可以构造出不是alpha_numberic的参数,其中通过xor 0xff可以构造比较大的数,因为0xff可以通过'dec esi'即零减一得到,比较方便。然后最终构造出来的shellcode也就56bytes - -
exp: https://paste.ubuntu.com/p/WMDWnSSbPt/
Starbound
startbound好像是一个游戏,题目程序就是个命令行版的(感觉就是个2D版的MC),因为是个真正可以玩的游戏所以要逆向的工作量会有点大,当时花了一段时间逆了大部分后才发现漏洞就在main函数里。
首先要说一下程序的菜单功能,图中的menu_now(名字是我乱取的)其实是个全局的函数指针,会有别的函数设置这个变量来显示不同的菜单;同样menu_option_now(名字也是我乱取的)是当前菜单对应的几个功能的函数指针,这里的index其实有个挺明显(但不知道为什么我一开始没发现)的溢出,输入10以上或负数可以执行别的函数,因为是bss上的,所以负数的话刚好可以执行玩家name的地方,name可以在setting里设置,可设置成ROP或程序自带的函数。
本来这种情况最简单的做法就是one_gadget了,但题目没有给libc,于是想到另一个方法(解法应该不唯一),先执行一个"add esp, 0x1c"的ROP打乱stack,再使nptr造成溢出用常规的栈溢出方法来做。其实写ROP时也需要用到libc的,可以用DynELF泄露,但更简单的方法是查libc_database。
exp: https://paste.ubuntu.com/p/kFgjY66594/
BabyStack
实际上就是个栈溢出,不过覆盖ret value要绕过几个限制。
首先是登录,而且有一个magic copy的功能需要先登录成功才能进入。登录的话会把输入的密码和一串16bytes的随机密钥进行对比,在对比时用了strncmp函数,所以如果输回车的话可以直接登录成功。利用一下strncmp还可以进行密钥的爆破(程序的初始化中alarm了半个小时应该也暗示了要爆破的了),要爆破密钥是因为main退出时会检查密钥有没被更换,有的话会触发__stack_chk_fail,跟canary一样。除了密钥能爆破外,爆破一下16bytes密钥后面的内容可以拿到程序基址,方便写ROP。
然后是magic copy,里面用到了个不怎么安全的strcpy函数,而它的dest是main函数的一个buffer(局部变量,64bytes,栈上),src是这个函数里的局部变量而且有128bytes,所以可以造成main函数的栈溢出。但magic copy函数里只能输入63bytes,所以ROP其实是登录的函数里输的,利用登录函数返回后栈没有被清掉。
然后就是普通的栈溢出做法了。因为main只能溢出3句ROP,23个bytes(而且我自己操作时不知道为什么会被零截断),所以可以利用一下rdi保留的栈地址和程序自带的输入函数(大概是像readn那样的那个)来输入更长的ROP。
exp: https://paste.ubuntu.com/p/62zfW6n2WM/
(这应该是我跑得最久的exp了 - -)
Spirited Away
一道看似是堆题的栈溢出题(而且canary也是关的),是一个写影评的程序(?),只有一个函数,漏洞就是在survey函数中输出已经有多少条评论时用到了sprintf函数,由于buf大小是56bytes,如果cnt是三位数的话会造成buf溢出了一位,刚好会把'n'覆盖到name和comment读入时设定的大小的那个变量(叫它nclen吧- -),所以name和comment的输入大小从60变成了110,造成了栈上的溢出。
另外,刚开始时由于comment和reason(就是放评论和原因的那两个变量)在栈上,而且输入的时候末尾没有设置0,巧妙利用一下可以泄露栈地址和libc基址。在comment溢出后,可以覆盖到name的指针前泄露heap基址(虽然后来发现这个没什么用- -)。
由于reason的读入大小是由另一个变量控制的,所以不能直接控制reason溢出(reason是最后一个,溢出才能覆盖返回地址),因为栈地址可以泄露出来,所以想到可以在reason里造一个假堆块,然后覆盖name指针到这个假块,最后free-malloc就把name变到reason里了,由于name的读入大小也改了,所以读入name就可以造成stack overflow。给了库其实可以直接one_gadget的,但远程泄露libc_base时被坑了一下,栈上选了几个才能用,还以为是one_gadget出问题了,才搞了普通ROP(- -)。
exp: https://paste.ubuntu.com/p/3KfTFWFpMb/
Secret Garden
堆题。在remove那里free掉name后没有置0,所以可以造成double free,感觉做法应该不唯一,我用的是fastbin attack的做法。
首先fastbin attack可以泄露堆地址,再来一个unsortedbin或smallbin的可以泄露libc基址,用fastbin attack可以改掉堆上某个flower的name指针,造成任意位置的读,可以读libc上environ的stack地址,然后读栈上的内容就可以读到各种东西了。最后在raise函数的栈里找个合适的地方,malloc一个fastbin大小的块就可以造成栈溢出覆盖返回地址,然后one_gadget get shell。
还有,由于用的时libc2.23,找大小时可以错位,由于64位程序的栈地址和libc地址开头都是0x7f,所以选择大小时0x70的块最合适,还有chunk的大小是int类型的,所以看4个bytes就好了,实际操作中发现想写的地方最后一个byte是随机的,需要一点运气才能跑出来,反正就是不知道怎么的就搞出来了 - -
exp: https://paste.ubuntu.com/p/DND5mn586W/
才搞了十五题,还是太菜了啊
流下没技术的眼泪.jpg