题录1.0
刷题记录1
因为国赛将近,开始每天几道题,难度不等,之后会有patch的使用(算是预告和DIR-815的复现(早就复现一直没时间详细写
babyfengshui_33c3_2016
是一道风水题,可以拿来找回感觉
静态分析
1 | void __cdecl __noreturn main() |
是一个很常规的菜单堆
可以分析出一个结构体
1 | struct Node{ |
他是首先会malloc一个堆作为存储des,然后再malloc 0x80来存储name和des堆的地址
主要的漏洞点在于edit函数中
1 | unsigned int __cdecl sub_8048724(unsigned __int8 a1) |
他的数据判断主要是通过地址的判断
思路
1.首先申请连续的3个结构体,description部分空间大小为0x80,方便计算:
堆块0 des 0x80 | 堆块0 node 0x80 | 堆块1 des 0x80 | 堆块1 node 0x80 | 堆块2 des 0x8 | 堆块2 node 0x80 |
---|---|---|---|---|---|
2.释放第一个结构体,得到一个空闲的0x100的堆块:
空闲堆块0 x100 | 堆块1 des 0x80 | 堆块1 node 0x80 | 堆块2 des 0x8 | 堆块2 node 0x80 |
---|---|---|---|---|
3.申请新的结构体,其description部分为0x100,根据linux堆的性质,会优先分配空闲的堆块,释放得到的空闲堆块可以满足description的空间需求,而node的空间需要新分配,得到下面的结构:
堆块0 des 0x100 | 堆块1 des 0x80 | 堆块1 node 0x80 | 堆块2 des 0x8 | 堆块2 node 0x80 | 堆块0 node 0x80 |
---|---|---|---|---|---|
之后绕过只需要des的大小输入中间跨过的堆的大小就能实现堆溢出了
1 | from pwn import* |
至少本地通了(汗,远程太old了
护网杯_2018_gettingstart
1 | __int64 __fastcall main(int a1, char **a2, char **a3) |
算是一个趣味题,是覆盖v5为7FFF…FFF然后覆盖v6为0.1就可以getshell,主要是v6的double型转换比较复杂(千万不要用gpt做这种工作。。。。。
浮点型:https://tooltt.com/floatconverter/
就有exp:
1 | from pwn import* |
axb_2019_heap
满保护
静态分析
1 | int __cdecl __noreturn main(int argc, const char **argv, const char **envp) |
首先是一个菜单堆
1 | unsigned __int64 banner() |
banner函数中有一个栈溢出和格式化字符串漏洞,但是由于Canary的保护,他是无法进行栈溢出的,因此只能泄露了,而泄露的话一次性泄露code基址和libc基址
1 | unsigned __int64 add_note() |
其中漏洞点在于get_input函数:
1 | size_t __fastcall get_input(__int64 a1, int a2) |
一个off-by-one
这样还有edit,delete可以有思路即unlink改free_hook为system,之后free(‘/bin/sh\x00’)即可(但是好像(lll¬ω¬)key没用到)
1 | from pwn import* |
oneshot_tjctf_2016
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
注意:long int在linux是8字节的,在windows是4字节的(无论32 or 64)
这里首先是让我们输入v4的值然后泄露v4作为地址其上内容的值,之后还能再次输入v4的值,之后以v4为函数基址执行函数,就想到首先先泄露libc然后执行one_gadget(属实可供操控的内容较少只能试试看
1 | from pwn import* |
也算是运气不错,一把过
wustctf2020_number_game
1 | unsigned int vulnerable() |
本题要绕过第一个if然后就能实现shell了,那绕过变成了困难,首先v1是int型范围在-2147483648~2147483647之间,那么如果取-2147483648他的原码是0x80000000,而取反是取补码然后+1,所以他的补码也是0x80000000,就能实现shell
starctf_2019_babyshell
这题算是一个\x00的妙用:
1 | __int64 __fastcall main(__int64 a1, char **a2, char **a3) |
可以执行shellcode但是要先绕过if的检查
而检查
1 | __int64 __fastcall sub_400786(_BYTE *a1) |
却非常阴间,如果真的按照这个去执行,很难才能get shell,笔者还是太菜了,想不出来看了网上大佬的wp,发现我只注意for循环却没注意到第一个while(*a1)只要让这个为假就能跳过了,因此在shell开头扔个\x00即可跳过检查,再后面搭配几个字节码凑个汇编之后加上自己的shellcode就可以getshell了
1 | from pwn import* |
https://defuse.ca/online-x86-assembler.htm#disassembly这可以实现机器码转汇编,因为要找\x00之后接的机器码后的汇编。。
还是太菜了,任重而道远。。。
gyctf_2020_some_thing_exceting
CISCN-2023 烧烤摊儿
1 | // local variable allocation has failed, the output may be wrong! |
1 | __int64 __fastcall menu(__int64 a1, __int64 a2, int a3, int a4, int a5, int a6) |
发现当own为真时有新的选项
1 | __int64 gaiming() |
其中有个栈溢出
1 | __int64 pijiu() |
发现这个计算钱的方式很奇怪,当买的为负数时,会加钱,而加钱可以买摊位,然后就有栈溢出
1 | from pwn import* |
算是非常简单的题目了
[CISCN 2023 初赛]funcanary
1 | void __fastcall __noreturn main(__int64 a1, char **a2, char **a3) |
首先是父子进程的
1 | unsigned __int64 sub_128A() |
这里面会溢出0x10个字节,但显然要爆破Canary,而
有个后门函数,但是要绕过Pie,直接覆盖尾巴3字节第四个字节爆破即可
1 | from pwn import* |
但是远程打不通,不知道为什么,canary爆破不出来,很奇怪
[LitCTF 2023]狠狠的溢出涅~
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
漏洞很简单,strlen绕过即可,给了Libc,利用libc的ropchain即可
老规矩先puts出libc基址之后直接绕过
1 | from pwn import* |
或者
1 | from pwn import* |
因为他的字符是0x200限制的因此要缩短一下(不是pop rax用不起,而是add更有feeling(bushi