本文最后更新于:2021-11-26 下午
Hello CTF
详细分析
先查壳,看到无壳,可以直接打开。
使用IDA打开,可以看到我们输入的被转为十六进制最终存储在了v10
之中,然后和v13
比较,我们可以看到这部分的值是
437261636b4d654a757374466f7246756e
那么只需要将这部分十六进制值转为字符就行了,就是flag。
注册机
| int main() { unsigned char flag[] ="\x43\x72\x61\x63\x6b\x4d\x65\x4a\x75\x73\x74\x46\x6f\x72\x46\x75\x6e"; printf("%s", flag); }
|
得到flag
CrackMeJustForFun
insanity
查看文件可以知道是32位的elf文件
使用IDA打开,看到非常简短的main函数,前面会生成一个随机数,然后可以看到str
是个数组,生产的随机数除以0xA的余数作为下标,来决定puts
函数输出什么。
看一下str
数组,可以看到flag就在其中,第一个就是flag,当然如果运气好,随机数正好是0xA的倍数也可以自己输出flag。
9447{This_is_a_flag}
python-trade
详细分析
是一个pyc文件,在网上找一个反编译pyc的网站,查看反编译后的Python代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
import base64
def encode(message): s = '' for i in message: x = ord(i) ^ 32 x = x + 16 s += chr(x) return base64.b64encode(s)
correct = 'XlNkVmtUI1MgXWBZXCFeKY+AaXNt' flag = '' print 'Input flag:' flag = raw_input() if encode(flag) == correct: print 'correct' else: print 'wrong'
|
根据python代码写出注册机,算出flag
注册机
python
| from base64 import *
flag = "XlNkVmtUI1MgXWBZXCFeKY+AaXNt" flag = b64decode(flag) s= "" for i in flag: i = (i - 16) ^ 32 s += chr(i) print(s)
|
C
| int main() { unsigned char flag[] = "^SdVkT#S ]`Y\\!^)\x8f\x80ism"; for (int i = 0; i < 21; i++) { flag[i] = (flag[i] - 16) ^ 32; } printf("%s", flag); }
|
nctf{d3c0mpil1n9_PyC}
re1
查壳,无壳,32位的程序
使用IDA打开分析,看到我们输入的值字符串会和v5.m128i_i8
进行比较,查看其中的值
查看得到flag,注意这里是小端序
DUTCTF{We1c0met0DUTCTF}
game
详细分析
查壳,无壳
这是一个游戏,需要把所有的灯都点亮,才可以输出flag。
使用OD调试,搜索字符串可以看到flag成功输出的这里,只要能够运行到这里就可以了。
可以直接在函数头部右键,选择此处为新的EIP,然后直接跑起来,flag就会自己出来。
也可以修改之前的跳转条件,让程序可以运行到输出flag的地方。
注册机
使用IDA查看,可以看到如果满足所有的条件就会进入sub_457AB4
这是生成flag的地方,可以根据这里写出注册机。
| int main() { unsigned char v5[] = "\x12\x40\x62\x05\x02\x04\x06\x03\x06\x30\x31\x41\x20\x0C\x30\x41" "\x1F\x4E\x3E\x20\x31\x20\x01\x39\x60\x03\x15\x09\x04\x3E\x03\x05" "\x04\x01\x02\x03\x2C\x41\x4E\x20\x10\x61\x36\x10\x2C\x34\x20\x40" "\x59\x2D\x20\x41\x0F\x22\x12\x10"; unsigned char v2[] = "\x7B\x20\x12\x62\x77\x6C\x41\x29\x7C\x50\x7D\x26\x7C\x6F\x4A\x31" "\x53\x6C\x5E\x6C\x54\x06\x60\x53\x2C\x79\x68\x6E\x20\x5F\x75\x65" "\x63\x7B\x7F\x77\x60\x30\x6B\x47\x5C\x1D\x51\x6B\x5A\x55\x40\x0C" "\x2B\x4C\x56\x0D\x72\x01\x75\x7E"; for (int i = 0; i < 56; i++) { v2[i] = v2[i] ^ 0x13; v2[i] = v2[i] ^ v5[i]; } printf("%s", v2); }
|
zsctf{T9is_tOpic_1s_v5ry_int7resting_b6t_others_are_n0t}
open-source
打开题目是一个C的源代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| #include <stdio.h> #include <string.h>
int main(int argc, char *argv[]) { if (argc != 4) { printf("what?\n"); exit(1); }
unsigned int first = atoi(argv[1]); if (first != 0xcafe) { printf("you are wrong, sorry.\n"); exit(2); }
unsigned int second = atoi(argv[2]); if (second % 5 == 3 || second % 17 != 8) { printf("ha, you won't get it!\n"); exit(3); }
if (strcmp("h4cky0u", argv[3])) { printf("so close, dude!\n"); exit(4); }
printf("Brr wrrr grr\n");
unsigned int hash = first * 31337 + (second % 17) * 11 + strlen(argv[3]) - 1615810207; printf("Get your key: "); printf("%x\n", hash); return 0; }
|
根据源码分析可以知道需要输入三个参数,三个参数满足条件后就会输出flag。
- 第一个参数是
51966
- 第二个参数除以5 余数不能是3,除以17余数要等于8
- 第三个参数,等于
h4cky0u
根据条件求第二个参数,有很多,选择其中一个
python:
| for i in range(1,100): if(i % 5 != 3 and i % 17 == 8): print(i)
|
得到flag
c0ffee
simple-unpack
查壳,可以看到是UPX的壳
直接使用upx-d
脱壳
使用IDA打开,直接看到flag
flag{Upx_1s_n0t_a_d3liv3r_c0mp4ny}
logmein
详细分析
64位elf文件,无壳
使用IDA打开。可以明显的看到具体的比较地方,和flag生成的方式。&v7+i%v6,其中v6是7,也就是&v7+i%7,将v7转换为字符,一共就是七个,而i取7的余数,这里就是在不断的获取v7的每一位来与v8进行异或。
注册机
根据上面的分析写出注册机
| int main() { unsigned char a[] = "\x68\x61\x72\x61\x6D\x62\x65"; char flag[] = ":\"AL_RT^L*.?+6/46"; for (int i = 0; i < strlen(flag); i++) { flag[i] = flag[i] ^ (a[i % 7]); } printf("%s", flag); return 0; }
|
RC3-2016-XORISGUD
no-strings-attached
查壳,无壳,32位elf文件
使用IDA打开,分析发现关键函数是authenticate
看到输入被曝存在ws之中,然后wcscmp
会比较s2和ws,s2是经过decrypt
函数生成的。
查看具体的算法,看到是非常简单的减法。
数据为图中框起来的数据循环的减去1-5这几个数(因为都带着0x14,所以直接可以去掉0x14的)
注册机
| int main() { unsigned char s[] = "\x3A\x36\x37\x3B\x80\x7A\x71\x78\x63\x66\x73\x67\x62\x65\x73\x60\x6B\x71\x78" "\x6A\x73\x70\x64\x78\x6E\x70\x70\x64\x70\x64\x6E\x7B\x76\x78\x6A\x73\x7B\x80"; int a[] = { 1,2,3,4,5 }; for (int i = 0; i < 38; i++) { s[i] -= a[i % 5]; } printf("%s", s); return 0; }
|
9447{you_are_an_international_mystery}
getit
无壳,64位ELF文件
使用IDA打开,看到主要的流程是打开/tmp/flag.txt,然后向其中写入一些东西,但是最后又调用remove
函数将其删除,所以是不可能查看flag.txt的,那么就看一下其写入的数据。看图中框选起来的部分可以看到,将s数组的每一位通过+1或者-1放在了t的十位以后的位置。
查看s与t
注册机
| int main() { char flag[] = "c61b68366edeb7bdce3c6820314b7498"; int tmp = 0; for (int i = 0; i < 32; i++) { if ((i & 1) != 0) { flag[i] += 1; } else flag[i] -= 1; } printf("SharifCTF{%s}", flag); return 0; }
|
SharifCTF{b70c59275fcfa8aebf2d5911223c6589}
csaw2013reversing2
详细分析
查壳,无壳
直接运行程序,看到会弹出一个窗口,但是其中都是乱码根本不可读
使用IDA打开,看到lpMem就是那段乱码,正常流程都是弹窗显示这串字符,注意到sub_401000
函数,其传入了参数lpMem
在其中对于lpMem进行了操作,可以看到主要是异或,并且四个字符作为一组来进行异或。
原始数据以及异或用的KEY
注册机
| int main() { unsigned char a[] = "\xBB\xAA\xCC\xDD"; unsigned char flag[] = "\xBB\xCC\xA0\xBC\xDC\xD1\xBE\xB8\xCD\xCF\xBE\xAE\xD2\xC4\xAB\x82\xD2\xD9\x93\xB3\xD4\xDE\x93\xA9\xD3\xCB\xB8\x82\xD3\xCB\xBE\xB9" "\x9A\xD7\xCC\xDD"; for (int i = 0; i < 36; i++) { flag[i] = flag[i] ^ a[i%4]; printf("%c", flag[i]); } return 0; }
|
flag{reversing_is_not_that_hard!}
maze
无壳,64位的elf文件
限制是必须是输入24位,前五位是“nctf{”,最后一位是“}”
看到最终成功的条件是,一系列操作之后asc_601060[8 * v9 + v10[0]]
中的值正好等于”#”,
查看前面的流程,看到对于上面这个数组的位移来说,输入O
是-1,o
是+1,.
是-8,0
是+8
此数组,也就是说是一个8*8的迷宫,需要走到”#”的位置。
如图中这样的迷宫,这样走可以走到“#”,然后带入前面的几个走的字符,得到flag
nctf{o0oo00O000oooo..OO}