2022hufuCTF
qemu题还没入门,一点头绪都没有,rust几乎没解就没看,这次比赛的收获大概是入门了go pwn,又学了几个libc的奇技淫巧
gogogo
Go二进制文件逆向分析从基础到进阶——Tips与实战案例 - 安全客,安全资讯平台 (anquanke.com)
这篇文章关于go的分析该讲的都讲了,首先恢复符号的IDA插件
这个插件有个bug,就是得先点try to detemine go version based on moduledata,再选版本,然后rename functions才行
how to fix it? · Issue #20 · sibears/IDAGolangHelper (github.com)
然后这题的main.main是个幌子(因为断点断不下来),前面安全客的文章里也讲了,main.main之前还有各种
init函数会被执行,乱找了一通,真实逻辑再math.init里面
这个函数里面有很多这种一大片的,其引用的字符串会在某处修复,这里静态看是不正常的,动调这种一块是打印一个字符串
题目逻辑是两个猜数字,第一个静态分析就能得到
第二个是随机生成4个10以内的数字,就是下面这个游戏
猜数字(古老的的密码破译类益智类小游戏)_百度百科 (baidu.com)
有脚本可以直接用
猜完了回来会来个菜单,这个垃圾菜单,考虑了半天,以为漏洞在里面,调了半天内存分配,都是走的go的gc,不存在漏洞
搜了很多go pwn的资料发现go的pwn清一色的都是栈溢出,就一个个的试,最后在程序退出前,这里发现了栈溢出
这里Read是往栈上缓冲区读的
所以这题就是裸栈溢出,直接打ROP即可
exp
exp如下
1 | #!python |
ROP部分可以参考这里
[原创] CTF2019Q1 第八题 挖宝 writeup-CTF对抗-看雪论坛-安全社区|安全招聘|bbs.pediy.com
[原创]挖宝题目设计思路-CTF对抗-看雪论坛-安全社区|安全招聘|bbs.pediy.com
/bin/sh可以利用这个gadget写到栈上
mva
题目名字倒过来就是avm,虚拟机pwn题
题目比较裸,一些点如下,
1 | 0~5 6个寄存器 |
当时只找到一个明显的负数溢出洞,case14中只判断了r2的范围在0~5,对于r1只判断<5
因此我们能向下写,在reg_mem下面的就是堆栈指针sp_reg了,
但是push中对堆栈指针进行了检测,必须小于0x100,这样也没法修改到返回地址,也就是这个洞的效果就是向下写,能想到的就只有程序里面的虚拟机的跳表了,但是涉及到很多问题,难以实现
第二个洞是队友发现的,还是在push里,依然是负数的问题
假如我们想加0x104,我们可以给他加上1<<63,这样其就是负数(注意这里并不是-0x104),只是让这里认为是负数实现绕过,负多少无所谓,下面这里乘2的时候直接就绕过了,1<<63乘到1<<64正好溢出,就没了,剩下的是我们原来的数*2,
因为main函数的返回地址恰好是libc里面的libc_start_main_ret也就是+231的位置
所以我们直接通过漏洞修改返回地址的后8位为one_gadget ogg(读返回地址到寄存器里面)提前算好应该加还是减
exp
exp如下
1 | #!python |
babygame
经典栈溢出结合格式化字符串
但是以前做过先格式化字符串泄露信息(canary,libc),然后栈溢出直接打rop的
这题反过来了,先栈溢出然后再格式化字符串
main函数里read buf 0x256,buf只有256字节大小,明显栈溢出
guess_game是跟系统石头剪刀布,必须输100次,虽然用了rand随机产生,但是通过栈溢出我们可以把种子改了
这里game过了之后进入geshihua函数,这里明显格式化字符串
利用思路是,填满堆栈到rbp的位置,然后打印就可以得到main函数rbp的地址,也就是一个栈地址,等到进入sub_13F7时,我们可以通过这里得到的rbp计算到13F7的返回值在栈上的地址,
这里的格式化字符串即承担了泄露信息(canary,libc)的功能,又改了函数返回值为start,
等到其返回时又会执行一遍start,然后执行main函数,此时再根据已经泄露的信息打栈溢出rop
由于ASLR的存在,程序基址会变,所以start的地址1180的最高位1是不确定的,要多打几次
exp
exp如下
1 | #!python |
这一步就是看ASLR是否随机到了我们打的地址
1 | # debug('b *$rebase(0x1449)') |
这里我假定的地址是0x55555554000,那start就是0x5184, 后面得到程序base时判断是否是4000,不是就重打
1 | rdi = base + 0x15D3 |
这里pop rdi是0x15D3 0x15D4是ret,为什么rop要多加个ret,这个问题我一直都遇到过,不多加这个ret,do-system会报错,
据说是对齐的问题,困惑
这里多学了个调用c函数的技巧
1 | def game(): |