二进制作业第三周
RE
拔丝溜四(NewstarsCTF2022)
~~题在这里:~~https://buuoj.cn/match/matches/146/challenges#%E6%8B%94%E4%B8%9D%E6%BA%9C%E8%82%86%20(easy)
这个题,对base64进行了魔改…
首先,分析题目,从start入口寻找main:
从这里的Code=某个函数()继续进入(既然是给返回代码赋值,那么很有可能就是main入口)
这里的j_main是我命名成main的,后来IDA又重新分析为j_main(),进入真正的main后就可以正式分析了,
实际上代码就是对输入的长度为42的flag进行魔改的base64编码,编码结果就是main中那个显而易见的str2:
第29行的encode()也是自己修改的函数名,魔改的base64()编码就是这里进行
进入后发现不是普通的base64,encode()将flag分成若干组,3个一组分别进行编码,但是每一组都使用不同的编码字符表—也就是所谓的变表加密
再次进入循环中的第一句函数调用中,发现有一个rand(),实际从逻辑上考虑肯定不可能是随机的,否则不会出现那个固定的base64结果,所以联想到对srand()调用时输入了某个固定的种子,但是我这里没有看出来哪个是srand()函数的调用(我太菜了)
于是我使用动态调试的方法,一个个的把求字符表的偏移值v1求出来:
在这里设断点后,直到运行完,把所有的v1出现过的值写成python列表就可以写解密脚本了:
1 | import base64 |
运行结果:
但是比赛结束了没办法提交flag…
结束…
EzTea(NewstarsCTF2022)
这个题顾名思义,Tea加密…
去分析代码就能知道,要对输入的串(之所以不说字符串是因为加密解密还是说字节串比较好)进行加密,然后与一个9*sizeof(int32_t)==36字节长度的加密后的串进行比较,也就是说这个加密的串就是加密后的flag.
那么我们要分析程序的加密算法,容易得知这是TEA系列的加密算法,而且通过加密中的<<4和>>4可以知道是TEA目前优化最好的(貌似?)XXTEA加密(不过MX还是要自己改的)
写出逆向解密脚本:
1 |
|
运行结果:
结束…
BabyAlgorithm
这个题没啥好说的,就是RC4,然后我非要自己写脚本…费老半天
按照顺序把S-box(key)之类的求出来就行
我的代码:
1 |
|
但是我们实际上知道RC4的加解密的过程是相同的…
所以代码实际上基本不用改…
正解代码:
1 |
|
运行的结果是一样的:
然后复制到python的解密脚本中转换成utf-8的字符串就行,不过貌似没有base64的事…
1 | import base64 |
运行结果:
1 | E:\devtools\venu\Scripts\python.exe D:\Data\CTF\do\re_run.py |
结束…
slices
这题简单…因为没题干把题目的源代码也放上来吧…
题目代码:
1 |
|
就这么简单,写个脚本就行了:
1 | flag = ['0'] * 32 |
不出意外的话答案应该没啥问题…(解密脚本写的不咋地…)
hope{i_l0ve_pyth0n_slic3s_a_l0t}
结束…
super anti scalper solution 9000
这个题就是JS混淆,代码很简单,我们其实只需要一件事:
JS中任何对象都是true…
还有一件事:
!![]把[]转换为布尔值,又[]是一个对象,所以他是true,然后!取反,!再取反,所以!![]的值就是true
还有一件事:
!![]+!![]对2个true进行相加,显然true是1,那么答案就是1+1
所以首先就把!![]全部换成1,方便查看:其实不替换也行…
很显然,输入的字符串就是n,然后在第27行进行了比较,所以其实直接把27行n===后面那一串输出就行…
运行结果(记得按一下按钮):
hope{sHoe_1ddbf55508afcc08_sold!}
结束…
open-source
这题…给了代码…那就不是题了…
解释直接放注释了,运行出来的结果就是flag:
1 |
|
运行结果:
结束…
PWN
not_the_same_3dsctf_2016
我只能说这个题对于我有点新了…貌似有两个做法,但是第一个做法那个exit()不太会搞,先放了吧…
方法一
这个题,乍一看是一个ret2next,但是…一开始本地能跑通,远程不过…后续发现大概是缓冲区刷新的问题,于是让printf继续返回到exit()以进行缓冲区刷新即可通过
开幕雷击(爽击)…gets()就躺在那里,所以我们肯定是要从main开始ret,不过注意一个问题,那就是没有push ebp了(具体去看main的汇编)
但是除此之外没有调用任何的函数,那就去找吧,去尝试找"flag"字符串发现第一个就是,然后双击过去到汇编(?),接下来按Ctrl+x快捷键跳转到使用了这个字符串的函数,发现是一个get_secret()函数:
有一个flag.txt文件相关的字符串:
双击过去:
ctrl+x跳转,然后f5查看:
这个函数将flag.txt写入了fl4g这个地方(可寻址),那么我们接下来的事就是想办法跳转到get_secret()然后再用printf或者write之类的输出就行:
1 | from pwn import * |
本地创建一个flag.txt测试一下没问题,然后把p32(1)改成p32(exit_addr),远程也能通过了:
或者这样用fflush也行,不过那个stdout的地址不是直接找到的那个,调试找出来的,先记录一下再说:
1 | from pwn import * |
这个用fflush也行,就是stdout这个文件指针一下子没找到正确的那个
方法二
这个应该是正解吧…或者可能是出题人疏忽了没搞三件套?(啥是三件套QWQ)
ret2shell的做法:
首先用checksec看看,发现有NX保护
然后IDA中发现了mprotect():
int mprotect(void *addr, size_t len, int prot)
三个参数分别是修改的起始地址,长度,修改为的权限
首先用这个函数去把.bss提权为可写权限(直接用7就行)
然后利用read进行shellcode的植入(read函数进行unix的读写)
接着就跳转到shellcode的位置进行getshell即可
注意:因为参数为3个,所以需要一个pop三连+ret的指令,这里用
ROPgadget --binary not_the_same_3dsctf_2016 --only 'pop|ret' | grep pop
来获取,随便一个就行,例如:
代码如下:
1 | from pwn import * |
参见:
(不是一个题,但是做法差不多一样…)
结束…
inndy_rop
这道题是rop…ret2syscall…
ROPgadget是真的好用啊…
那么我正好看了某个文章:
https://repw.github.io/2018/10/27/栈溢出之ROP基础/#undefined
关于系统调用号:
截图取自:https://blog.csdn.net/kaiandshan/article/details/44587225
题目分析:
代码非常简单,直接从一个overflow函数中gets()溢出,但是发现没有system()这些可利用的东西
所以是一个rop的题,那么既然是rop,就去用ROPgadget找rop
首先,最粗暴的方法就是直接用ROPgadget的一个奇葩功能直接生成shellcode,然后粘贴进脚本,加上偏移就行…
ROPgadget --binary rop --ropchain
使用该命令就会自动生成rop链,粘贴进脚本:
1 | from pwn import * |
运行没有问题:
然后我想自己构造(具体知识见百度[ctf rop]…):
1 | pop_eax_ret_addr = 0x080b8016 |
但是sh_addr不行,因为sys_execve()要使用’/bin/bash’,所以这里应该手动注入:
截图取自https://blog.csdn.net/qq_73149934/article/details/128430238
这里先放个记录,回头再看看
cmcc_simplerop
这个题也是rop,不过用ROPgadget生成的shellcode跑不通,手动写的syscall可以过
checksec发现没有PIE,开了NX
题目很简单,就是直接让read溢出,这里的思路是用系统调用11来用execve进行getshell
先计算个偏移(IDA里直接看的有误):
生成一串数字复制下来然后调试:
输入那串字符:
这里提示了一个无效地址,然后再运行这个命令:
找到偏移32(即0x20)
接下来分析rop,用ROPgadget发现没有’/bin/sh\x00’这个字符串,所幸有read函数,那么首先要用栈溢出将返回地址返回到read函数来将其注入到.bss段(这道题没有开启PIE,bss的地址就是绝对地址)
如此有第一段payload如下:
1 | # ret to read() --- read '/bin/sh' |
再接下来就是系统调用,知识见inndy_rop的WP:
1 | # syscall --- execve |
最后记得要多加一个字符串的输入:
1 | p.sendline('/bin/sh\x00') |
最后总的代码如下:
1 | from pwn import * |
运行结果:
结束…
canary1
关于canary…百度复习吧…
绕过方法:
1.大量fork的题: 使用逐字节爆破的方法
2.字符串输出泄露canary
3.GOT表劫持
但是…这道题是假的canary!!!
虽然checksec显示有canary…但是…
看汇编也能看出来,xor的结果根本就没有用到,下面是无条件跳转到call之后:
而且实际编写脚本也能发现0x20的输入长度根本不足以溢出到覆盖所谓canary的开头的00字节:
所以实际上就是个常规溢出,这里是syscall的getshell方式,而且题目中已经存在’/bin/sh’了…
本来这个题原本是用字符串溢出来泄露canary的…但是被某大佬patch掉了…orz
代码如下:
1 | from pwn import * |
运行结果:
结束…