鸽了好久了。
0x01 smd-50
输入字符串,md5后若为780438d5b6e29db0898bc4f0225935c0则输出正确
但是输入grape不对。
这是因为grape两次md5后才得到780438d5b6e29db0898bc4f0225935c0,而题目中要md5一次就得到780438d5b6e29db0898bc4f0225935c0。卡在这里了。
看了题解才醒悟,将grape md5一次后的得到的字符串,不就可以md5一次得到780438d5b6e29db0898bc4f0225935c0吗。
flag就是b781cbb29054db12f88f08c6e161c199,没有前缀。
比较简单,可惜我脑袋没转过弯来。
0x02 Shuffle
直接拿到flag。
这种题太浪费时间了。
(话不要说得太满。——《毛选》)
0x03 re2-cpp-is-awesome
题目描述:他们说c++是复杂的,证明他们说的是错的!
忍不住吐槽:其实他们说的是对的。。。
主函数:
看着花里胡巧的是吧。
其实那些很长的语句,大多是c++的STL,逆向的时候看着是长,但是正向编程的时候就是一个简单的函数或方法。
这道题比较基础,我没怎么看懂其中的STL,也能做出来
关键代码
char_2是char_1,而char_1
初步估计就是输入的字符串
判断输入字符串和off_6020A0[dword_6020C0[i_1]]是否相等。off_6020A0是字符型指针,指向
dword_6020C0是int数组。
所以就是从dword_6020C0中获取偏移量,再在字符串中获取字符,与输入字符串逐一比较。
获取dword_6020C0的IDC脚本
static main()
{
auto i,fp;
fp = fopen("d:\\1.txt","wb");
auto start = 0x6020c0;
auto size = 0x60213B - 0x6020c0;
for(i=start;i<start+size;i++)
{
fputc(Byte(i),fp);
}
fp.close();
}
解密脚本
s = r'''L3t_ME_T3ll_Y0u_S0m3th1ng_1mp0rtant_A_{FL4G}_W0nt_b3_3X4ctly_th4t_345y_t0_c4ptur3_H0wev3r_1T_w1ll_b3_C00l_1F_Y0u_g0t_1t'''
n = []
with open('1.txt', 'rb')as f:
data = f.read()
for i,b in enumerate(data):
if i % 4 == 0:
n.append(b)
flag = ''
for i in n:
flag += s[i]
print(flag)
ALEXCTF{W3_L0v3_C_W1th_CL45535}
是不是逻辑很简单?
0x04 crackme
见到了一个新壳,nsPack,网上找了个脱壳工具。
傻瓜式脱壳
不过好像脱的不是很干净,ida打开时弹出几个报错窗口
不过还是能正常加载出函数来的。
很简单的异或。
a = [0x74] + [ord(i) for i in 'his_is_not_flag']
b = [0x12,4,8,0x14,0x24,0x5c,0x4a,0x3d,0x56,0x0a,0x10,0x67,0,0x41,0,1,0x46,0x5a,0x44,0x42,0x6e,0x0c,0x44,0x72,0x0c,0x0d,0x40,0x3e,0x4b,0x5f,2,1,0x4c,0x5e,0x5b,0x17,0x6e,0x0c,0x16,0x68,0x5b,0x12]
for i in range(42):
print(chr(a[i % 16] ^ b[i]),end='')
0x05 re-for-50-plz-50
本题考查mips架构下的逆向。
https://blog.csdn.net/yang_hong_/article/details/51016867
这种汇编我没接触过,肯定看不懂呀。
看了题解才发现,就是字符串异或0x37。
x86,x86-64都还没学好,这类型的题先放一放吧。
s = 'cbtcqLUBChERV[[Nh@_X^D]X_YPV[CJ'
for i in s:
print(chr(ord(i) ^ 0x37),end='')
Reversing-x64Elf-100
加密算法:移位后+1.
很简单的算法。
解密脚本:
v3 = "Dufhbmf"+"pG`imos"+"ewUglpt"
a1 = ''
for i in range(12):
a1 += v3[(i%3)*7 + (2*(i//3))]
for i in a1:
print(chr(ord(i)-1),end='')
最初是用c++写的(就是把IDA中的代码改了改),但是不正确。原因在于v3,v4,v5的地址未必连续。
错误脚本:
#include <iostream>
using namespace std;
int main(){
signed int i; // [rsp+14h] [rbp-24h]
const char *v3; // [rsp+18h] [rbp-20h]
const char *v4; // [rsp+20h] [rbp-18h]
const char *v5; // [rsp+28h] [rbp-10h]
char a1[16];
v3 = "Dufhbmf";
v4 = "pG`imos";
v5 = "ewUglpt";
for ( i = 0; i <= 11; ++i ){
a1[i] = (&v3)[i % 3][2 * (i / 3)];
}
for ( i = 0; i <= 11; ++i ){
cout<<char(a1[i]-1);
}
return 0;
}
IgniteMe
主函数:
看着花里胡巧的,其实关键代码不多。
sub_4011C0:
没啥可说的,直接放解密脚本:
byte_4420B0 = [0x0d,0x13,0x17,0x11,0x2,0x1,0x20,0x1d,0x0c,0x2,0x19,0x2f,0x17,0x2b,0x24,0x1f,0x1e,0x16,0x9,0x0f,0x15,0x27,0x13,0x26,0x0a,0x2f,0x1e,0x1a,0x2d,0x0c,0x22,0x4]
string = list(map(ord, 'GONDPHyGjPEKruv{{pj]X@rF'))
flag = []
for i in range(24):
flag.append((((string[i] ^ byte_4420B0[i]) - 72) ^ 0x55) & 0x7f)
print(flag)
for i in range(len(flag)):
if 65 <= flag[i] <= 90:
flag[i] += 32
elif 97 <= flag[i] <= 122:
flag[i] -= 32
print(''.join(map(chr, flag)))
注意一点,异或的运算优先级低于减号。我被这一点坑了十分钟。
srm-50
简直就是明文存储的flag.
把上图中的字符读出来,就是flag.
Windows_Reverse1
加密后的字符串已知,加密如下:
很简单的替换,只是byte_402ff8无法看到数据。
动态轻松获取:
s = ' '*32 + '~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)(\'&%$#"!'
ss = 'DDCTF{reverseME}'
flag = ''
for i in range(len(ss)):
flag += chr(s.index(ss[i]))
print(flag)
拿到flag{ZZ[JX#,9(9,+9QY!}
后,我没敢提交,没见过这么怪的flag(swpuctf2019 mobile2除外)
Guess-the-Number
JAVA逆向,有手就行。
parallel-comparator-200
给出c源码
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#define FLAG_LEN 20
void * checking(void *arg) {
char *result = malloc(sizeof(char));
char *argument = (char *)arg;
*result = (argument[0]+argument[1]) ^ argument[2];
return result;
}
int highly_optimized_parallel_comparsion(char *user_string)
{
int initialization_number;
int i;
char generated_string[FLAG_LEN + 1];
generated_string[FLAG_LEN] = '\0';
while ((initialization_number = random()) >= 64);
int first_letter;
first_letter = (initialization_number % 26) + 97;
pthread_t thread[FLAG_LEN];
char differences[FLAG_LEN] = {0, 9, -9, -1, 13, -13, -4, -11, -9, -1, -7, 6, -13, 13, 3, 9, -13, -11, 6, -7};
char *arguments[20];
for (i = 0; i < FLAG_LEN; i++) {
arguments[i] = (char *)malloc(3*sizeof(char));
arguments[i][0] = first_letter;
arguments[i][1] = differences[i];
arguments[i][2] = user_string[i];
pthread_create((pthread_t*)(thread+i), NULL, checking, arguments[i]);
}
void *result;
int just_a_string[FLAG_LEN] = {115, 116, 114, 97, 110, 103, 101, 95, 115, 116, 114, 105, 110, 103, 95, 105, 116, 95, 105, 115};
for (i = 0; i < FLAG_LEN; i++) {
pthread_join(*(thread+i), &result);
generated_string[i] = *(char *)result + just_a_string[i];
free(result);
free(arguments[i]);
}
int is_ok = 1;
for (i = 0; i < FLAG_LEN; i++) {
if (generated_string[i] != just_a_string[i])
return 0;
}
return 1;
}
int main()
{
char *user_string = (char *)calloc(FLAG_LEN+1, sizeof(char));
fgets(user_string, FLAG_LEN+1, stdin);
int is_ok = highly_optimized_parallel_comparsion(user_string);
if (is_ok)
printf("You win!\n");
else
printf("Wrong!\n");
return 0;
}
所以线程返回的每个result都是0
所以异或结果为0
即differences[i] + first_letter == flag[i]
differences = [0, 9, -9, -1, 13, -13, -4, -11, -9, -1, -7, 6, -13, 13, 3, 9, -13, -11, 6, -7]
just_a_string = [115, 116, 114, 97, 110, 103, 101, 95, 115, 116, 114, 105, 110, 103, 95, 105, 116, 95, 105, 115]
for i in range(26):
first_letter = 97+i
#print(first_letter)
flag = []
for k in range(len(just_a_string)):
#temp = (differences[k] + first_letter) ^ just_a_string[k]
temp = differences[k] + first_letter
flag.append(temp)
print(''.join(map(chr, flag)))
secret-galaxy-300
算是个脑洞题,没有明显的flag提示。
int __libc_csu_gala()
{
int result; // eax
sc[0] = off_409014;
sc[3] = &byte_40DAC0;
sc[1] = 31337;
sc[2] = 1;
byte_40DAC0 = off_409004[0][8];
byte_40DAC1 = off_409010[0][7];
byte_40DAC2 = off_409008[0][4];
byte_40DAC3 = off_409004[0][6];
byte_40DAC4 = off_409004[0][1];
byte_40DAC5 = off_409008[0][2];
byte_40DAC6 = 95;
byte_40DAC7 = off_409004[0][8];
byte_40DAC8 = off_409004[0][3];
byte_40DAC9 = off_40900C[0][5];
byte_40DACA = 95;
byte_40DACB = off_409004[0][8];
byte_40DACC = off_409004[0][3];
byte_40DACD = off_409004[0][4];
byte_40DACE = off_409010[0][6];
byte_40DACF = off_409010[0][4];
byte_40DAD0 = off_409004[0][2];
byte_40DAD1 = 95;
byte_40DAD2 = off_409010[0][6];
result = *((unsigned __int8 *)off_409008[0] + 3);
byte_40DAD3 = off_409008[0][3];
byte_40DAD4 = 0;
return result;
}
程序初始化的时候通过从别的字符串拼出flag。
simple-check-100
给了三个文件,一样的源码,只是平台不同。
经过分析,输入与flag无关,所以但nop掉相关的函数,直接打印flag.
但是windows上的结果是这样的:
我又去分析了一遍,确实应该输入与flag是无关的。
!!!最后nop了linux64的那个程序,拿到flag。
我服了。上题之前不检验下题目的正确性吗?
Mysterious
vs窗口程序。
经过尝试,输入长度为7的字符串的时候会有动作。
x32dbg附加,然后回溯栈,来到40117c
int __stdcall sub_401090(HWND hWnd, int a2, int a3, int a4)
{
int v4; // eax
char Source; // [esp+50h] [ebp-310h]
CHAR Text[4]; // [esp+154h] [ebp-20Ch]
char v8; // [esp+159h] [ebp-207h]
__int16 v9; // [esp+255h] [ebp-10Bh]
char v10; // [esp+257h] [ebp-109h]
int Value; // [esp+258h] [ebp-108h]
CHAR input; // [esp+25Ch] [ebp-104h]
char v13; // [esp+25Fh] [ebp-101h]
char v14; // [esp+260h] [ebp-100h]
char v15; // [esp+261h] [ebp-FFh]
memset(&input, 0, 0x104u);
Value = 0;
if ( a2 == 16 )
{
DestroyWindow(hWnd);
PostQuitMessage(0);
}
else if ( a2 == 273 )
{
if ( a3 == 0x3E8 )
{
GetDlgItemTextA(hWnd, 1002, &input, 260);
strlen(&input);
if ( strlen(&input) > 6 )
ExitProcess(0);
v4 = atoi(&input);
Value = v4 + 1;
if ( v4 == 0x7A && v13 == 0x78 && v15 == 0x7A && v14 == 0x79 )
{
strcpy(Text, "flag");
memset(&v8, 0, 0xFCu);
v9 = 0;
v10 = 0;
_itoa(Value, &Source, 10);
strcat(Text, "{");
strcat(Text, &Source);
strcat(Text, "_");
strcat(Text, "Buff3r_0v3rf|0w");
strcat(Text, "}");
MessageBoxA(0, Text, "well done", 0);
}
SetTimer(hWnd, 1u, 0x3E8u, TimerFunc);
}
if ( a3 == 1001 )
KillTimer(hWnd, 1u);
}
return 0;
}
前面几个字符动调分析拿到。0x401152和0x40118a下个断点,慢慢分析。
经过分析,前几个字符是122xyz
answer_to_everything
脑洞题
交flag{#kdudpeh}
或flag{kdudpeh}
都不对
网上查了下,题目描述
暗示交sha1...
flag{sha1(kdudpeh)}
即flag{80ee2a3fe31da904c596d993f7f1de4827c1450a}
RE-100
多线程。
首尾是{}
然后分四段
第一段是53fc275d81,第四段是4938ae4efd,但是下一个判断确是整个输入是{daf29f59034938ae4efd53fc275d81053ed5be8c}
不过前面有个!confuseKey(bufParentRead, 42),进去看看。
所以顺序重新调整为3,4,1,2
53fc275d81
053ed5be8c
daf29f5903
4938ae4efd
提交flag是{53fc275d81053ed5be8cdaf29f59034938ae4efd},去掉{}
tt3441810
给出:
00400080 68 66 6C 00 00 48 BF 01 00 00 00 00 00 00 00 48
00400090 8D 34 24 48 BA 02 00 00 00 00 00 00 00 48 B8 01
004000A0 00 00 00 00 00 00 00 0F 05 68 61 67 00 00 48 BF
004000B0 01 00 00 00 00 00 00 00 48 8D 34 24 48 BA 02 00
004000C0 00 00 00 00 00 00 48 B8 01 00 00 00 00 00 00 00
004000D0 0F 05 68 7B 70 00 00 48 BF 01 00 00 00 00 00 00
004000E0 00 48 8D 34 24 48 BA 02 00 00 00 00 00 00 00 48
004000F0 B8 01 00 00 00 00 00 00 00 0F 05 68 6F 70 00 00
00400100 48 BF 01 00 00 00 00 00 00 00 48 8D 34 24 48 BA
00400110 02 00 00 00 00 00 00 00 48 B8 01 00 00 00 00 00
00400120 00 00 0F 05 68 70 6F 00 00 48 BF 01 00 00 00 00
00400130 00 00 00 48 8D 34 24 48 BA 02 00 00 00 00 00 00
00400140 00 48 B8 01 00 00 00 00 00 00 00 0F 05 68 70 72
00400150 00 00 48 BF 01 00 00 00 00 00 00 00 48 8D 34 24
00400160 48 BA 02 00 00 00 00 00 00 00 48 B8 01 00 00 00
00400170 00 00 00 00 0F 05 68 65 74 00 00 48 BF 01 00 00
00400180 00 00 00 00 00 48 8D 34 24 48 BA 02 00 00 00 00
00400190 00 00 00 48 B8 01 00 00 00 00 00 00 00 0F 05 68
004001A0 7D 0A 00 00 48 BF 01 00 00 00 00 00 00 00 48 8D
004001B0 34 24 48 BA 02 00 00 00 00 00 00 00 48 B8 01 00
004001C0 00 00 00 00 00 00 0F 05 48 31 FF 48 B8 3C 00 00
004001D0 00 00 00 00 00 0F 05
一看就是某种小众的汇编,但是题目没有任何描述。
所以只能当成misc来做了
0x68这个字节码的作用应该是存储一个word.
import struct
with open(r'rev100', 'r')as f:
b = f.read()
data = b''
for line in b.split('\n'):
temp = line[len('00400080 '):].split(' ')
for i in temp:
if i:
data += struct.pack('B', int(i, 16))
for i in range(len(data)):
if data[i] == ord('h'):
print('{}{}'.format(chr(data[i+1]), chr(data[i+2])), end='')
提交去掉flag{}
流浪者
看雪ctf2019的一道题,估计是签到题。
看图标,好像是pascal写的。
打表0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
验证。
所以就是一个简单的置换密码。
a = 'KanXueCTF2019JustForhappy'
b = 'abcdefghiABCDEFGHIJKLMNjklmn0123456789opqrstuvwxyzOPQRSTUVWXYZ'
c = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
flag = ''
for i in a:
temp = b.index(i)
flag += c[temp]
print(flag)
666
水题
cipher = list(map(ord, 'izwhroz""w"v.K".Ni'))
key = 0x12
flag = []
for i in range(0, len(cipher), 3):
print(i)
flag.append((key ^ cipher[i]) - 6)
flag.append((key ^ cipher[i+1]) + 6)
flag.append(key ^ cipher[i+2] ^ 6)
print(''.join(map(chr, flag)))
SignIn
逆向里考察rsa
用到了GMP(The GNU Multiple Precision Arithmetic Library)又叫GNU多精度算术库。
n才256bit,直接yafu.
c = 0xad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35
n = 103461035900816914121390101299049044413950405173712170434161686539878160984549
e = 65537
'''
分解自yafu
P39 = 366669102002966856876605669837014229419
P39 = 282164587459512124844245113950593348271
'''
from Crypto.Util.number import *
p = 366669102002966856876605669837014229419
q = 282164587459512124844245113950593348271
phi = (p-1)*(q-1)
d = inverse(e, phi)
m = pow(c, d, n)
print(long_to_bytes(m))