BUUCTF Reverse WriteUp 2

简单注册器

是个APK,使用dex2jar反编译之后用jd(java decompiler)查看内容

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package com.example.flag;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends ActionBarActivity {
protected void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle);
setContentView(2130903063);
if (paramBundle == null)
getSupportFragmentManager().beginTransaction().add(2131034172, new PlaceholderFragment()).commit();
Button button = (Button)findViewById(2131034175);
final TextView textview = (TextView)findViewById(2131034174);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View param1View) {
int i = 1;
String str = editview.getText().toString();
if (str.length() != 32 || str.charAt(31) != 'a' || str.charAt(1) != 'b' || str.charAt(0) + str.charAt(2) - 48 != 56)
i = 0;
if (i == 1) {
char[] arrayOfChar = "dd2940c04462b4dd7c450528835cca15".toCharArray();
arrayOfChar[2] = (char)(arrayOfChar[2] + arrayOfChar[3] - 50);
arrayOfChar[4] = (char)(arrayOfChar[2] + arrayOfChar[5] - 48);
arrayOfChar[30] = (char)(arrayOfChar[31] + arrayOfChar[9] - 48);
arrayOfChar[14] = (char)(arrayOfChar[27] + arrayOfChar[28] - 97);
for (i = 0;; i++) {
String str1;
if (i >= 16) {
str1 = String.valueOf(arrayOfChar);
textview.setText("flag{" + str1 + "}");
return;
}
String str2 = str1[31 - i];
str1[31 - i] = str1[i];
str1[i] = str2;
}
}
textview.setText("");
}
});
}

public boolean onCreateOptionsMenu(Menu paramMenu) {
getMenuInflater().inflate(2131492864, paramMenu);
return true;
}

public boolean onOptionsItemSelected(MenuItem paramMenuItem) {
return (paramMenuItem.getItemId() == 2131034176) ? true : super.onOptionsItemSelected(paramMenuItem);
}

public static class PlaceholderFragment extends Fragment {
public View onCreateView(LayoutInflater param1LayoutInflater, ViewGroup param1ViewGroup, Bundle param1Bundle) {
return param1LayoutInflater.inflate(2130903064, param1ViewGroup, false);
}
}
}

输入字符进行校验,符合条件的,就把这个字符串几位数进行操作之后取反,写个脚本跑一下

1
2
3
4
5
6
7
8
9
s = 'dd2940c04462b4dd7c450528835cca15'
s = list(s)
s = [ord(x) for x in s]
s[2] = (s[2] + s[3] - 50)
s[4] = (s[2] + s[5] - 48)
s[30] = (s[31] + s[9] - 48)
s[14] = (s[27] + s[28] - 97)
s.reverse()
print(''.join([chr(x) for x in s]))

出了flag{59acc538825054c7de4b26440c0999dd}

lucky guy

下载下来的结果是个X86-64的ELF,发现F5失败

image-20200801230102154

得,那就分析汇编,发现是一个输入数字,然后取随机数出flag的

找到出flag的逻辑,都不用打patch,直接手动分析就是了

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
unsigned __int64 get_flag()
{
unsigned int v0; // eax
char v1; // al
signed int i; // [rsp+4h] [rbp-3Ch]
signed int j; // [rsp+8h] [rbp-38h]
__int64 s; // [rsp+10h] [rbp-30h]
char v6; // [rsp+18h] [rbp-28h]
unsigned __int64 v7; // [rsp+38h] [rbp-8h]

v7 = __readfsqword(0x28u);
v0 = time(0LL);
srand(v0);
for ( i = 0; i <= 4; ++i )
{
switch ( rand() % 200 )
{
case 1:
puts("OK, it's flag:");
memset(&s, 0, 0x28uLL);
strcat((char *)&s, f1);
strcat((char *)&s, &f2);
printf("%s", &s);
break;
case 2:
printf("Solar not like you");
break;
case 3:
printf("Solar want a girlfriend");
break;
case 4:
v6 = 0;
s = 'fo`guci';
strcat(&f2, (const char *)&s);
break;
case 5:
for ( j = 0; j <= 7; ++j )
{
if ( j % 2 == 1 )
v1 = *(&f2 + j) - 2;
else
v1 = *(&f2 + j) - 1;
*(&f2 + j) = v1;
}
break;
default:
puts("emmm,you can't find flag 23333");
break;
}
}
return __readfsqword(0x28u) ^ v7;
}

f1可以直接找到,写个脚本出f2

1
2
3
4
5
6
7
8
9
10
11
s = 'fo`guci'
s = list(s)
s = [ord(x) for x in s]
s.reverse()
for i in range(8):
if i%2==1:
s[i] -= 2
else:
s[i] -= 1
f1 = 'GXY{do_not_'
print(f1 + ''.join([chr(x) for x in s]))

出结果GXY{do_not_hate_me}

rsa

下载下来是一个key一个enc,rsa算法就是要去找e,d,还有欧拉函数

key里面是一个base64的公钥,enc打不开,估计是加密后的字节串,有了公钥key,而且长度不算长,就可以带入到factordb.com里面去找一下因数分解,然后求欧拉函数

1
2
3
4
5
6
import base64

N = 'MDwwDQYJKoZIhvcNAQEBBQADKwAwKAIhAMAzLFxkrkcYL2wch21CM2kQVFpY9+7+/AvKr1rzQczdAgMBAAE='
N = base64.b64decode(N)
N = [hex(x)[2:].zfill(2) for x in N]
print('0x'+''.join(N))

key = 0x303c300d06092a864886f70d0101010500032b003028022100c0332c5c64ae47182f6c1c876d42336910545a58f7eefefc0bcaaf5af341ccdd0203010001

查到了因式分解的结果

7246255757203408838535614667498219793647193424559346880212407078558298027963762366749937521991103661174290022755026478321354431589 * 3^6 * 7 * 53 * 70957 * 277198451

欧拉函数可以出来了

phi = 0x1b0ae025206ee6e222bc368d42f8eed88d062df5ab5f7cc8d9bcca82519cbbdd8dc1354991b61e95e1109843ececeb5954dd14e0c086175c7aedeb8ace00L

然后就是求phi关于65537的逆元,就是我们的d

d = gmpy.invert(65537, phi)

得到d = 0x6bdf061f1331506dde814a5a543d0b056806ae6ebc1d3a7737978f7828753e3099b58c0adbe3ce3db07bb1e7c2c1904dd7e7cdd07c2a6825cf78218ca01

得到了d之后只需要对密文进行
$$
cipher^{d} % N=plain
$$
然后就是读取文件enc转化为hex了

1
2
3
4
5
c = ''
with open('rsa\\41c4e672-98c5-43e5-adf4-49d75db307e4\\output\\flag.enc', 'rb') as f:
c = f.read()
c = [hex(x)[2:].zfill(2) for x in c]
print('0x'+''.join(c))

c = 0x4196c0594a5e000a96b878b67cd724795b13a8f2ca54da06d0f19c28be689b62

然后就是pow(c, d, N),结果是0x10b2ee66d8c3be7d67bbeb85060700e9e4f598f627f746931aadb7a7bc17db0d573267c99c8e326e5e8458b63794ccc20493d26bfc0d147028808b91a6c0

???这根本不是可以解出来的字符串啊

用在线rsa加解密出来也完全不是什么东西啊

得,网上找了下在线公钥分析,发现公钥解析错了,不能直接用我的方法直接从base64来解析,他这个还有固定格式的

拖进http://tool.chacuo.net/cryptrsakeyparse里面,得到

n = C0332C5C64AE47182F6C1C876D42336910545A58F7EEFEFC0BCAAF5AF341CCDD

分解得到 285960468890451637935629440372639283459304008741604601924494328155975272418463

然后就是算欧拉函数phi = 81176168860169991027846870170527607562179635470395365333547868786951080991441L

求出逆元d = 0xb378155840fb2b8fbdd869db5b7e91994f1ece256ee1175ec2c2bd3a4a795ad1

最后解密还得靠python的rsa模块来对文件进行解密,其实这个最难不是解密,是配置gmpy2的环境,嗨,说多了都是泪啊,windows下我现在还没配好

1
2
3
4
5
6
7
8
9
10
11
12
13
import rsa
import gmpy2

n = 0xC0332C5C64AE47182F6C1C876D42336910545A58F7EEFEFC0BCAAF5AF341CCDD
e = 0x10001
p = 285960468890451637935629440372639283459
q = 304008741604601924494328155975272418463
phi = 81176168860169991027846870170527607562179635470395365333547868786951080991441
d = 0xb378155840fb2b8fbdd869db5b7e91994f1ece256ee1175ec2c2bd3a4a795ad1
privKey = rsa.PrivateKey(n, e, d, p, q)
with open('./flag.enc', 'rb') as f:
content = f.read()
print(rsa.decrypt(content, privKey))

最后flagflag{decrypt_256}

这不应该是crypto题吗……

CrackRTF

记事本图标的exe,x86平台,拖进IDA,找到main函数逻辑

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
int main_0()
{
DWORD v0; // eax
DWORD v1; // eax
CHAR pass2; // [esp+4Ch] [ebp-310h]
int v4; // [esp+150h] [ebp-20Ch]
CHAR s; // [esp+154h] [ebp-208h]
BYTE pass1; // [esp+258h] [ebp-104h]

memset(&pass1, 0, 0x104u);
memset(&s, 0, 0x104u);
v4 = 0;
printf("pls input the first passwd(1): ");
scanf("%s", &pass1);
if ( strlen((const char *)&pass1) != 6 )
{
printf("Must be 6 characters!\n");
ExitProcess(0);
}
v4 = atoi((const char *)&pass1);
if ( v4 < 100000 )
ExitProcess(0);
strcat((char *)&pass1, "@DBApp");
v0 = strlen((const char *)&pass1);
j_sha1(&pass1, v0, &s);
if ( !_strcmpi(&s, "6E32D0943418C2C33385BC35A1470250DD8923A9") )
{
printf("continue...\n\n");
printf("pls input the first passwd(2): ");
memset(&pass2, 0, 0x104u);
scanf("%s", &pass2);
if ( strlen(&pass2) != 6 )
{
printf("Must be 6 characters!\n");
ExitProcess(0);
}
strcat(&pass2, (const char *)&pass1);
memset(&s, 0, 0x104u);
v1 = strlen(&pass2);
j_getMd5((BYTE *)&pass2, v1, &s);
if ( !_strcmpi("27019e688a4e62a649fd99cadaafdb4e", &s) )
{
if ( !(unsigned __int8)sub_40100F(&pass2) )
{
printf("Error!!\n");
ExitProcess(0);
}
printf("bye ~~\n");
}
}
return 0;
}

看了一下逻辑,大概是对第一个字符串加盐hash,然后成功了之后拼到第二个字符串上面,我居然没查到这个hash和md5,只能暴力破解了

1
2
3
4
5
6
7
8
import hashlib
salt = '@DBApp'

for i in range(100000, 1000000):
data = str(i)+salt
hash_sha1 = hashlib.sha1(data.encode())
if hash_sha1.hexdigest().upper() == '6E32D0943418C2C33385BC35A1470250DD8923A9':
print(data)

爆出来第一个是123321,第二个继续爆,发现不是数字,直接查

~!3a@0123321@DBApp出来了,然而不对???

继续跟进去看看这个第三个判断函数

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
char __cdecl sub_4014D0(LPCSTR lpString)
{
LPCVOID lpBuffer; // [esp+50h] [ebp-1Ch]
DWORD NumberOfBytesWritten; // [esp+58h] [ebp-14h]
DWORD nNumberOfBytesToWrite; // [esp+5Ch] [ebp-10h]
HGLOBAL hResData; // [esp+60h] [ebp-Ch]
HRSRC hResInfo; // [esp+64h] [ebp-8h]
HANDLE hFile; // [esp+68h] [ebp-4h]

hFile = 0;
hResData = 0;
nNumberOfBytesToWrite = 0;
NumberOfBytesWritten = 0;
hResInfo = FindResourceA(0, (LPCSTR)0x65, "AAA");
if ( !hResInfo )
return 0;
nNumberOfBytesToWrite = SizeofResource(0, hResInfo);
hResData = LoadResource(0, hResInfo);
if ( !hResData )
return 0;
lpBuffer = LockResource(hResData);
sub_401005(lpString, (int)lpBuffer, nNumberOfBytesToWrite);
hFile = CreateFileA("dbapp.rtf", 0x10000000u, 0, 0, 2u, 0x80u, 0);
if ( hFile == (HANDLE)-1 )
return 0;
if ( !WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, &NumberOfBytesWritten, 0) )
return 0;
CloseHandle(hFile);
return 1;
}

就是从程序本身的一个区段里面取出数据,同刚才的数据进行xor得到flag写入在dbapp.rtf里面,然后也懒得继续跟了,直接打开文件,出flag

Flag{N0_M0re_Free_Bugs}

pyre

下载下来是个pyc文件,直接uncompiler 反编译

uncompyle6.exe a.pyc > a.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# uncompyle6 version 3.7.2
# Python bytecode 2.7 (62211)
# Decompiled from: Python 3.7.0 (v3.7.0:1bf9cc5093, Jun 27 2018, 04:59:51) [MSC v.1914 64 bit (AMD64)]
# Embedded file name: encode.py
# Compiled at: 2019-08-19 21:01:57
print 'Welcome to Re World!'
print 'Your input1 is your flag~'
l = len(input1)
for i in range(l):
num = ((input1[i] + i) % 128 + 128) % 128
code += num

for i in range(l - 1):
code[i] = code[i] ^ code[(i + 1)]

print code
code = ['\x1f', '\x12', '\x1d', '(', '0', '4', '\x01', '\x06', '\x14', '4', ',', '\x1b', 'U', '?', 'o', '6', '*', ':', '\x01', 'D', ';', '%', '\x13']
# okay decompiling .\attachment.pyc

是个根本跑不起来的py2,而且这个code += num操作我是有点醉的,不晓得他是啥意思,我在python2/3里面都试过了一下,没啥用,报错,就猜他是code[i] += num

((a+b) % p + c) % p = (a + (b+c) % p) % p 可以优化一下里面的取余那一步

num = ((input1[i] + i) % 128 + 128) % 128 = (input1[i] + i) % 128(假定flag的长度不超多128)

而这个ascii最多有126个字符,那就好办了啊,写个脚本跑一下就出来了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import string
table = [ord(x) for x in string.printable]
code = ['\x1f', '\x12', '\x1d', '(', '0', '4', '\x01', '\x06', '\x14', '4',
',', '\x1b', 'U', '?', 'o', '6', '*', ':', '\x01', 'D', ';', '%', '\x13']
code = [ord(x) for x in code]
for i in range(len(code)-2, -1, -1):
code[i] ^= code[i+1]
for i in range(len(code)):
code[i] -= i
if code[i] not in table or code[i] <= 10:
code[i] += 128

print(code)
code = [chr(x) for x in code]
print(''.join(code))

GWHT{Just_Re_1s_Ha66y!}

younger driver

拖进PEID查壳,是个UPX的壳,脱壳机脱了,是个32位exe

主要函数逻辑比较清晰,改名后如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int main_0()
{
HANDLE v1; // [esp+D0h] [ebp-14h]
HANDLE hObject; // [esp+DCh] [ebp-8h]

j_inputFlag();
::hObject = CreateMutexW(0, 0, 0);
j_strcpy(input_dest, input_flag);
hObject = CreateThread(0, 0, StartAddress, 0, 0, 0);
v1 = CreateThread(0, 0, sub_41119F, 0, 0, 0);
CloseHandle(hObject);
CloseHandle(v1);
while ( indexer != -1 )
;
j_compare();
CloseHandle(::hObject);
return 0;
}

然后startAddress函数是用于变换的,最后的compare是用于比较变换后的flag和data是否相同

但是我电脑上没有MSVCRT100D.dll跑不起来,于是只好静态分析他的变换函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
char *__cdecl func1(int *input_flag, int *indexer)
{
char *result; // eax
char chr; // [esp+D3h] [ebp-5h]

chr = *(input_flag + indexer);
if ( (chr < 'a' || chr > 'z') && (chr < 'A' || chr > 'Z') )
exit(0);
if ( chr < 'a' || chr > 'z' )
{
result = data[0];
*(input_flag + indexer) = data[0][*(input_flag + indexer) - 0x26];
}
else
{
result = data[0];
*(input_flag + indexer) = data[0][*(input_flag + indexer) - 0x60];
}
return result;
}

他这个data就是键盘密码表,算法简而言之就是大写变小写小写变大写然后按照键盘顺序来加密

写个脚本爆破一下

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
34
import string

table = 'QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm' + '\0'
data = 'TOiZiZtOrYaToUwPnToBsOaOapsyS'


def decry(data):
ret = []
for i in data:
idx = table.find(i)
if i.islower():
ret.append(chr(idx + 0x60))
else:
ret.append(chr(idx + 0x26))
return ''.join(ret)

def encry(data:str):
ret = list(data)
for i in range(len(data)):
if data[i].isupper():
idx = ord(data[i]) - 0x26
else:
idx = ord(data[i]) - 0x60
ret[i] = table[idx]
return ''.join(ret)

flag = ''
for i in range(len(data)):
for j in string.ascii_letters:
if(encry(j) == data[i]):
flag += j
print(flag)
e = encry(flag)
print(e)

解出来flag是dhGsGsDhCeJdHfAiXdHwKhJhJIKEk,但是交了一下,居然不对……

可惜跑不了,不能debug,让我装一个msvcrt100d.dll看看能不能调出来,好家伙还加了反调试,他会检测你的进程列表里有没有odida之类的东西,但是我可用x32dbg啊

只是没有ida在旁边我比较难定位罢了,把这个给patch掉就好得多

patch完成,然后直接用ida调试我看看到底发生了什么

image-20200804003646479

然后就发现调不通,还有一个栈顶指针错误,OD里面跟到这儿也直接卡死,硬给patch直接报错,淦

看看多线程到底说了啥

得,问题就在这,有个互斥锁,等锁,变换,然后减一,又等锁,淦

出了,完整脚本如下

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
import string

table = 'QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm' + '\0'
data = 'TOiZiZtOrYaToUwPnToBsOaOapsyS'


def encry(data:str):
ret = list(data)
for i in range(len(data)):
if data[i].isupper():
idx = ord(data[i]) - 0x26
else:
idx = ord(data[i]) - 0x60
ret[i] = table[idx]
return ''.join(ret)

flag = ''
for i in range(len(data)):
for j in string.ascii_letters:
if(encry(j) == data[i]):
flag += j

mutex = 0
for i in range(len(flag)):
if mutex == 0:
print(data[i], end='')
mutex = 1
else:
print(flag[i], end='')
mutex = 0

ThisisthreadofwindowshahaIsES,最后一位会变成\0,影响不大,反正最后一位都会变成结束符,应该是多解,但是怎么交都交不对,随后看了下网上的wp,原来预设是E,比赛的时候最后一位什么都是对的,但是这个平台只是设置了E,淦

相册

提示是个病毒,不要安装到手机里,下载下来居然还有系统报毒,有点东西

是个手机apk,用dex2jar反编译然后用jd打开看看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static int sendMailByJavaMail(String paramString1, String paramString2, String paramString3) {
if (debug)
return 1;
Mail mail = new Mail(C2.MAILUSER, C2.MAILPASS);
mail.set_host("smtp.163.com");
mail.set_port("25");
mail.set_debuggable(true);
mail.set_to(new String[] { paramString1 });
mail.set_from(C2.MAILFROME);
mail.set_subject(paramString2);
mail.setBody(paramString3);
try {
if (mail.send()) {
Log.i("IcetestActivity", "Email was sent successfully.");
return 1;
}
} catch (Exception exception) {
Log.e("MailApp", "Could not send email", exception);
return 1;
}
Log.i("IcetestActivity", "Email was sent failed.");
return 1;
}

然后取C2里面找找

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
public class C2 {
public static final String CANCELNUMBER = "%23%2321%23";

public static final String MAILFROME;

public static final String MAILHOST = "smtp.163.com";

public static final String MAILPASS;

public static final String MAILSERVER = Base64.decode(NativeMethod.m());

public static final String MAILUSER = Base64.decode(NativeMethod.m());

public static final String MOVENUMBER = "**21*121%23";

public static final String PORT = "25";

public static final String date = "2115-11-1";

public static final String phoneNumber;

static {
MAILPASS = Base64.decode(NativeMethod.pwd());
MAILFROME = Base64.decode(NativeMethod.m());
phoneNumber = Base64.decode(NativeMethod.p());
}
}

然后去NativeMethod

1
2
3
4
5
6
7
8
9
10
package com.net.cn;

public class NativeMethod {
public static native String m();

public static native String p();

public static native String pwd();
}

得,是个外部方法,用apktools解压一下,找到so文件,拖进IDA

进入m方法,看见一个base64字符串,出结果

1
2
3
4
5
6
7
8
9
10
11
12
.text:00000C80 Java_com_net_cn_NativeMethod_m          ; DATA XREF: LOAD:00000174↑o
.text:00000C80 ; __unwind {
.text:00000C80 PUSH {R3,LR}
.text:00000C82 LDR R2, [R0]
.text:00000C84 LDR R1, =(aMtgymtg0njuxmj_0 - 0xC8E)
.text:00000C86 MOVS R3, #0x29C
.text:00000C8A ADD R1, PC ; "MTgyMTg0NjUxMjVAMTYzLmNvbQ=="
.text:00000C8C LDR R3, [R2,R3]
.text:00000C8E BLX R3
.text:00000C90 POP {R3,PC}
.text:00000C90 ; End of function Java_com_net_cn_NativeMethod_m
.text:00000C90

18218465125@163.com

2019红帽杯 easyRE

是个elf,用wsl跑起来啥都不弹出啊

通过字符串查找大法找到关键函数,然后从print都没有得情况来看,应该是strip过了

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
signed __int64 sub_4009C6()
{
char *v0; // rsi
char *v1; // rdi
__int64 input_len; // rax
signed __int64 result; // rax
unsigned __int64 v4; // rax
__int64 v5; // rax
__int64 v6; // ST10_8
__int64 v7; // ST18_8
__int64 v8; // ST20_8
__int64 v9; // ST28_8
__int64 v10; // ST30_8
__int64 v11; // ST38_8
__int64 v12; // ST40_8
__int64 v13; // ST48_8
__int64 v14; // ST50_8
__int64 v15; // ST58_8
int i; // [rsp+Ch] [rbp-114h]
char data[39]; // [rsp+60h] [rbp-C0h]
char input[32]; // [rsp+90h] [rbp-90h]
int v19; // [rsp+B0h] [rbp-70h]
char v20; // [rsp+B4h] [rbp-6Ch]
char v21; // [rsp+C0h] [rbp-60h]
char v22; // [rsp+E7h] [rbp-39h]
char v23; // [rsp+100h] [rbp-20h]
unsigned __int64 v24; // [rsp+108h] [rbp-18h]

v24 = __readfsqword(0x28u);
data[0] = 'I';
data[1] = 'o';
data[2] = 'd';
data[3] = 'l';
data[4] = '>';
data[5] = 'Q';
data[6] = 'n';
data[7] = 'b';
data[8] = '(';
data[9] = 'o';
data[10] = 'c';
data[11] = 'y';
data[12] = '';
data[13] = 'y';
data[14] = '.';
data[15] = 'i';
data[16] = '';
data[17] = 'd';
data[18] = '`';
data[19] = '3';
data[20] = 'w';
data[21] = '}';
data[22] = 'w';
data[23] = 'e';
data[24] = 'k';
data[25] = '9';
data[26] = '{';
data[27] = 'i';
data[28] = 'y';
data[29] = '=';
data[30] = '~';
data[31] = 'y';
data[32] = 'L';
data[33] = '@';
data[34] = 'E';
data[35] = 'C';
memset(input, 0, sizeof(input));
v19 = 0;
v20 = 0;
v0 = input;
sub_4406E0(0LL, input, 37LL);
v20 = 0;
v1 = input;
LODWORD(input_len) = strlen((const __m128i *)input);
if ( input_len == 0x24 )
{
for ( i = 0; ; ++i )
{
v1 = input;
LODWORD(v4) = strlen((const __m128i *)input);
if ( i >= v4 )
break;
if ( (unsigned __int8)(input[i] ^ i) != data[i] )
{
result = 0xFFFFFFFELL;
goto LABEL_13;
}
}
print("continue!");
memset(&v21, 0, 0x40uLL);
v23 = 0;
v0 = &v21;
sub_4406E0(0LL, &v21, 64LL);
v22 = 0;
v1 = &v21;
LODWORD(v5) = strlen((const __m128i *)&v21);
if ( v5 == 39 )
{
v6 = transf2((__int64)&v21);
v7 = transf2(v6);
v8 = transf2(v7);
v9 = transf2(v8);
v10 = transf2(v9);
v11 = transf2(v10);
v12 = transf2(v11);
v13 = transf2(v12);
v14 = transf2(v13);
v15 = transf2(v14);
v0 = fool;
v1 = (char *)v15;
if ( !(unsigned int)sub_400360(v15, fool) )
{
print("You found me!!!");
v1 = "bye bye~";
print("bye bye~");
}
result = 0LL;
}
else
{
result = 0xFFFFFFFDLL;
}
}
else
{
result = 0xFFFFFFFFLL;
}
LABEL_13:
if ( __readfsqword(0x28u) != v24 )
sub_444020(v1, v0);
return result;
}

其中这个off_6CC090是可以无数次base64解码最后获取到一篇文章https://bbs.pediy.com/thread-254172.htm讲的是如何挖坑,啊,那么我岂不是……淦

跟进这个transf1来看看,淦哦全是mm128,看的一脸懵逼,动态调试一下看看,原来是判断字符串长度的

然后就是构造一个输入了,亦或一下就出来了

Info:The first four chars are flag

???什么迷惑玩意,然后就是第二个输入,跟了一下,是循环base64之后要等于这个网址,怎么有种强烈的上当受骗的感觉

试试提交一下这个玩意,不对,我就很纳闷了……完全是被耍了啊

看看writeUP,原来fini段还藏着代码,找到main_fake下面一个函数,进去就是关键算法

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
34
35
36
37
__int64 __fastcall sub_400D35(__int64 a1, __int64 a2)
{
__int64 v2; // rdi
__int64 result; // rax
unsigned __int64 v4; // rt1
unsigned int *v5; // [rsp+Ch] [rbp-24h]
signed int i; // [rsp+14h] [rbp-1Ch]
int v7; // [rsp+24h] [rbp-Ch]
unsigned __int64 v8; // [rsp+28h] [rbp-8h]

v8 = __readfsqword(0x28u);
v2 = 0LL;
for ( v5 = (unsigned int *)((unsigned int)sub_43FD20(0LL) - (unsigned int)qword_6CEE38);
SHIDWORD(v5) <= 1233;
++HIDWORD(v5) )
{
v2 = (unsigned int)v5;
sub_40F790((unsigned int)v5);
sub_40FE60();
sub_40FE60();
LODWORD(v5) = (unsigned __int64)sub_40FE60() ^ 0x98765432;
}
v7 = (signed int)v5;
if ( ((unsigned __int8)v5 ^ data[0]) == 'f' && (HIBYTE(v7) ^ (unsigned __int8)MEMORY[0x6CC0A3]) == 'g' )
{
for ( i = 0; i <= 24; ++i )
{
v2 = (unsigned __int8)(data[i] ^ *((_BYTE *)&v7 + i % 4));
sub_410E90(v2);
}
}
v4 = __readfsqword(0x28u);
result = v4 ^ v8;
if ( v4 != v8 )
sub_444020(v2, a2);
return result;
}

跟不出个啥玩意,只知道最开始的是flag,前面对V5也有个对比,然后构造一下还原出完整的flag,我始终找不到进入这个for函数的方法,无论输入什么,只能静态分析,v5/v7是干啥的也不清楚,如果能直接分析的话就好多了

1
2
3
4
5
6
7
8
9
10
11
12
13
data = [  0x40, 0x35, 0x20, 0x56, 0x5D, 0x18, 0x22, 0x45, 0x17, 0x2F, 
0x24, 0x6E, 0x62, 0x3C, 0x27, 0x54, 0x48, 0x6C, 0x24, 0x6E,
0x72, 0x3C, 0x32, 0x45, 0x5B]
key= 'flag'
key = list(key)
key = [ord(x) for x in key]
for i in range(len(key)):
key[i] ^= data[i]

for i in range(len(data)):
data[i] ^= key[i % 4]

print(''.join([chr(x) for x in data]))

出flagflag{Act1ve_Defen5e_Test}

好坑啊,花了我一天的时间

BJDCTF JustRE

拖进IDA,通过寻找字符串找到关键函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
BOOL __stdcall DialogFunc(HWND hWnd, UINT a2, WPARAM a3, LPARAM a4)
{
CHAR String; // [esp+0h] [ebp-64h]

if ( a2 != 272 )
{
if ( a2 != 273 )
return 0;
if ( (_WORD)a3 != 1 && (_WORD)a3 != 2 )
{
sprintf(&String, aD, ++click_time);
if ( click_time == 19999 )
{
sprintf(&String, aBjdDD2069a4579, 19999, 0);
SetWindowTextA(hWnd, &String);
return 0;
}
SetWindowTextA(hWnd, &String);
return 0;
}
EndDialog(hWnd, (unsigned __int16)a3);
}
return 1;
}

点击次数到了19999就会弹出flag?让我试试这个flag,出了???什么鬼,上面的题这么坑,这个题这么简单,居然排在上面的题目后面

SUCTF2019 signin

是个x86_64的elf,直觉告诉我这种一般都不好搞,虽然只有为数不多的函数

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
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
char n; // [rsp+0h] [rbp-4A0h]
char e; // [rsp+10h] [rbp-490h]
char m; // [rsp+20h] [rbp-480h]
char c; // [rsp+30h] [rbp-470h]
char input; // [rsp+40h] [rbp-460h]
char v9; // [rsp+B0h] [rbp-3F0h]
unsigned __int64 v10; // [rsp+498h] [rbp-8h]

v10 = __readfsqword(0x28u);
puts("[sign in]");
printf("[input your flag]: ", a2);
__isoc99_scanf("%99s", &input);
sub_96A(&input, &v9);
__gmpz_init_set_str(&c, "ad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35", 16LL);
__gmpz_init_set_str(&m, &v9, 16LL);
__gmpz_init_set_str(&n, "103461035900816914121390101299049044413950405173712170434161686539878160984549", 10LL);
__gmpz_init_set_str(&e, "65537", 10LL);
__gmpz_powm((__int64)&m, (__int64)&m, (__int64)&e, (__int64)&n);
if ( (unsigned int)__gmpz_cmp(&m, &c) )
puts("GG!");
else
puts("TTTTTTTTTTql!");
return 0LL;
}

难不成是考察gmpz库的辨认?看这个加密算法有点像是rsa

已知
$$
n=0Xe4bcdf0332b194a4c28376b1a3c18bf8604a4dc3efe363e00708c402d510e9e5\
e = 0X10001\
c = 0Xad939ff59f6e70bcbfad406f2494993757eee98b91bc244184a377520d06fc35
$$
求m,而$m=c^d % n$

直接分解p=282164587459512124844245113950593348271q=366669102002966856876605669837014229419

然后求得欧拉函数phi = (p-1)*(q-1)d = gmpy2.invert(65537, phi),得到d

m = pow(c, d, n),解得m = 0x73756374667b50776e5f405f68756e647265645f79656172737d

转化一下就出来了suctf{Pwn_@_hundred_years}

V&N2020 StrangeCPP

是个64位exe,吸取上次教训,不能忽略fini函数

然后果然找到了个假flag,然后有个特殊的段00cfg,进去也不知道是干什么的,淦,又是心灵感应题

找一下wp,原来是最开始main_fake在push数据的时候有可疑数据,跟进去

找到关键函数,动态调一下看看参数是啥

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
__int64 sub_7FF61FD83580()
{
__int64 *v0; // rdi
signed __int64 i; // rcx
__int64 result; // rax
__int64 v3; // [rsp+0h] [rbp-20h]
int v4; // [rsp+24h] [rbp+4h]
int j; // [rsp+44h] [rbp+24h]
__int64 v6; // [rsp+128h] [rbp+108h]

v0 = &v3;
for ( i = 82i64; i; --i )
{
*(_DWORD *)v0 = 0xCCCCCCCC;
v0 = (__int64 *)((char *)v0 + 4);
}
v6 = -2i64;
sub_7FF61FD810AA(&unk_7FF61FD97033);
result = sub_7FF61FD81384((unsigned int)key);
v4 = result;
if ( (_DWORD)result == 0x242EE21A && key <= 0xDE02EF )
{
for ( j = 0; j < 17; ++j )
{
putchar((unsigned __int8)(key ^ data[j]));
result = (unsigned int)(j + 1);
}
}
return result;
}

第一次没满足条件,跟进去的话key是8,跑一下看看,发现初步了解过,于是猜测最后一位是}得到key是64,然后就能够得到flagflag{MD5(theNum)}

猜num是就是key就是64,然后跑'64'和'@'的MD5都不对,然后进上面的函数跟一下,大概就是要解出这个方程

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
signed __int64 __fastcall solve_it(int key)
{
__int64 *v1; // rdi
signed __int64 i; // rcx
signed __int64 result; // rax
__int64 v4; // [rsp+0h] [rbp-20h]
int v5; // [rsp+24h] [rbp+4h]
int v6; // [rsp+44h] [rbp+24h]
unsigned int v7; // [rsp+64h] [rbp+44h]
int input; // [rsp+160h] [rbp+140h]

input = key;
v1 = &v4;
for ( i = 82i64; i; --i )
{
*(_DWORD *)v1 = -858993460;
v1 = (__int64 *)((char *)v1 + 4);
}
sub_1400110AA(&unk_140027033);
v5 = input >> 12;
v6 = input << 8;
v7 = (input << 8) ^ (input >> 12);
v7 *= 291;
if ( v7 )
result = v7;
else
result = 987i64;
return result;
}

要我们找到input是啥这里只涉及到v7,直接暴力求解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import hashlib
data = [ 0x26, 0x2C, 0x21, 0x27, 0x3B, 0x0D, 0x04, 0x75, 0x68, 0x34,
0x28, 0x25, 0x0E, 0x35, 0x2D, 0x69, 0x3D]
for i in range(len(data)):
data[i] ^= 64
print(''.join([chr(x) for x in data]))
result = 0x242EE21A

def enc(x):
return (0x123*(((x << 8) ^ (x >> 12))&0xffffffff)) & 0xffffffff

for x in range(0xDE02EF+1):
if enc(x) == result:
print('flag {}'.format(hashlib.md5(str(x).encode()).hexdigest().lower()))
break

e10adc3949ba59abbe56e057f20f883e出了

ACTF 2020 EasyRE

里面好多个几乎一样的文件,最外面那个是x86的exe,打不开,然后查壳是个UPX,上脱壳机

主函数非常清晰,希望不要是假flag那种坑把

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
34
35
36
37
38
39
40
41
42
43
44
int __cdecl main(int argc, const char **argv, const char **envp)
{
char idx[12]; // [esp+12h] [ebp-2Eh]
int v5; // [esp+1Eh] [ebp-22h]
int v6; // [esp+22h] [ebp-1Eh]
int v7; // [esp+26h] [ebp-1Ah]
__int16 input; // [esp+2Ah] [ebp-16h]
char v9; // [esp+2Ch] [ebp-14h]
char v10; // [esp+2Dh] [ebp-13h]
char v11; // [esp+2Eh] [ebp-12h]
int v12; // [esp+2Fh] [ebp-11h]
int v13; // [esp+33h] [ebp-Dh]
int v14; // [esp+37h] [ebp-9h]
char v15; // [esp+3Bh] [ebp-5h]
int i; // [esp+3Ch] [ebp-4h]

__main();
idx[0] = 42;
idx[1] = 70;
idx[2] = 39;
idx[3] = 34;
idx[4] = 78;
idx[5] = 44;
idx[6] = 34;
idx[7] = 40;
idx[8] = 73;
idx[9] = 63;
idx[10] = 43;
idx[11] = 64;
printf("Please input:");
scanf("%s", &input);
if ( (_BYTE)input != 65 || HIBYTE(input) != 67 || v9 != 84 || v10 != 70 || v11 != 123 || v15 != 125 )
return 0;
v5 = v12;
v6 = v13;
v7 = v14;
for ( i = 0; i <= 11; ++i )
{
if ( idx[i] != _data_start__[*((char *)&v5 + i) - 1] )
return 0;
}
printf("You are correct!");
return 0;
}

写个脚本出了,不知道是不是真的

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
idx = [0]*12
idx[0] = 42;
idx[1] = 70;
idx[2] = 39;
idx[3] = 34;
idx[4] = 78;
idx[5] = 44;
idx[6] = 34;
idx[7] = 40;
idx[8] = 73;
idx[9] = 63;
idx[10] = 43;
idx[11] = 64;
data_start = [0x7e,
0x7D, 0x7C, 0x7B, 0x7A, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74,
0x73, 0x72, 0x71, 0x70, 0x6F, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A,
0x69, 0x68, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0x61, 0x60,
0x5F, 0x5E, 0x5D, 0x5C, 0x5B, 0x5A, 0x59, 0x58, 0x57, 0x56,
0x55, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4F, 0x4E, 0x4D, 0x4C,
0x4B, 0x4A, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42,
0x41, 0x40, 0x3F, 0x3E, 0x3D, 0x3C, 0x3B, 0x3A, 0x39, 0x38,
0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x2F, 0x2E,
0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24,
0x23, 0x20, 0x21, 0x22, 0x00
]
flag = []
for i in range(len(idx)):
d = data_start.index(idx[i])
d += 1
flag.append(d)
print(''.join([chr(x) for x in flag]))

ACTF{U9X_1S_W6@T?}出了

GUET-CTF re

ELF-X86-64文件,加载开来只有几个函数,库函数都见不到,看参数应该是加了UPX的壳,脱了

关键函数

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
_BOOL8 __fastcall sub_4009AE(char *input)
{
if ( 1629056 * *input != 166163712 )
return 0LL;
if ( 6771600 * input[1] != 731332800 )
return 0LL;
if ( 3682944 * input[2] != 357245568 )
return 0LL;
if ( 10431000 * input[3] != 1074393000 )
return 0LL;
if ( 3977328 * input[4] != 489211344 )
return 0LL;
if ( 5138336 * input[5] != 518971936 )
return 0LL;
if ( 7532250 * input[7] != 406741500 )
return 0LL;
if ( 5551632 * input[8] != 294236496 )
return 0LL;
if ( 3409728 * input[9] != 177305856 )
return 0LL;
if ( 13013670 * input[10] != 650683500 )
return 0LL;
if ( 6088797 * input[11] != 298351053 )
return 0LL;
if ( 7884663 * input[12] != 386348487 )
return 0LL;
if ( 8944053 * input[13] != 438258597 )
return 0LL;
if ( 5198490 * input[14] != 249527520 )
return 0LL;
if ( 4544518 * input[15] != 445362764 )
return 0LL;
if ( 3645600 * input[17] != 174988800 )
return 0LL;
if ( 10115280 * input[16] != 981182160 )
return 0LL;
if ( 9667504 * input[18] != 493042704 )
return 0LL;
if ( 5364450 * input[19] != 257493600 )
return 0LL;
if ( 13464540 * input[20] != 767478780 )
return 0LL;
if ( 5488432 * input[21] != 312840624 )
return 0LL;
if ( 14479500 * input[22] != 1404511500 )
return 0LL;
if ( 6451830 * input[23] != 316139670 )
return 0LL;
if ( 6252576 * input[24] != 619005024 )
return 0LL;
if ( 7763364 * input[25] != 372641472 )
return 0LL;
if ( 7327320 * input[26] != 373693320 )
return 0LL;
if ( 8741520 * input[27] != 498266640 )
return 0LL;
if ( 8871876 * input[28] != 452465676 )
return 0LL;
if ( 4086720 * input[29] != 208422720 )
return 0LL;
if ( 9374400 * input[30] == 515592000 )
return 5759124 * input[31] == 719890500;
return 0LL;
}

每一位挨着挨着求就是了,想想能不能用正则表达式来自动化一下

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import re
text = """
_BOOL8 __fastcall sub_4009AE(char *input)
{
if ( 1629056 * *input != 166163712 )
return 0LL;
if ( 6771600 * input[1] != 731332800 )
return 0LL;
if ( 3682944 * input[2] != 357245568 )
return 0LL;
if ( 10431000 * input[3] != 1074393000 )
return 0LL;
if ( 3977328 * input[4] != 489211344 )
return 0LL;
if ( 5138336 * input[5] != 518971936 )
return 0LL;
if ( 7532250 * input[7] != 406741500 )
return 0LL;
if ( 5551632 * input[8] != 294236496 )
return 0LL;
if ( 3409728 * input[9] != 177305856 )
return 0LL;
if ( 13013670 * input[10] != 650683500 )
return 0LL;
if ( 6088797 * input[11] != 298351053 )
return 0LL;
if ( 7884663 * input[12] != 386348487 )
return 0LL;
if ( 8944053 * input[13] != 438258597 )
return 0LL;
if ( 5198490 * input[14] != 249527520 )
return 0LL;
if ( 4544518 * input[15] != 445362764 )
return 0LL;
if ( 3645600 * input[17] != 174988800 )
return 0LL;
if ( 10115280 * input[16] != 981182160 )
return 0LL;
if ( 9667504 * input[18] != 493042704 )
return 0LL;
if ( 5364450 * input[19] != 257493600 )
return 0LL;
if ( 13464540 * input[20] != 767478780 )
return 0LL;
if ( 5488432 * input[21] != 312840624 )
return 0LL;
if ( 14479500 * input[22] != 1404511500 )
return 0LL;
if ( 6451830 * input[23] != 316139670 )
return 0LL;
if ( 6252576 * input[24] != 619005024 )
return 0LL;
if ( 7763364 * input[25] != 372641472 )
return 0LL;
if ( 7327320 * input[26] != 373693320 )
return 0LL;
if ( 8741520 * input[27] != 498266640 )
return 0LL;
if ( 8871876 * input[28] != 452465676 )
return 0LL;
if ( 4086720 * input[29] != 208422720 )
return 0LL;
if ( 9374400 * input[30] == 515592000 )
return 5759124 * input[31] == 719890500;
return 0LL;
}
"""
text = text.split('\n')[1::2]

flag = []
for i in text:
if i[:2] == 'if':
numbers1 = re.findall("\d+ \*", i)[0][:-2]
numbers2 = re.findall("= \d+", i)[0][2:]
ch = int(numbers2) / int(numbers1)
flag.append(ch)

flag.append(719890500/5759124)
flag = [int(x) for x in flag]
print(''.join([chr(x) for x in flag]))

出了flag{e65421110b0a3099a1c039337},然后一交,不对,长度还是有点问题有个没匹配到,是input[6],而且还俩移位的

对flag改一下位置flag{e_65421110ba03099a1c039337},交了一下成功,是多解,但是这个平台还是判错,只能找wp了,淦

最后一位默认是1

FlareOn4 login

是个html,打开之后就是一个login登录框,有点东西

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE Html />
<html>
<head>
<title>FLARE On 2017</title>
</head>
<body>
<input type="text" name="flag" id="flag" value="Enter the flag" />
<input type="button" id="prompt" value="Click to check the flag" />
<script type="text/javascript">
document.getElementById("prompt").onclick = function () {
var flag = document.getElementById("flag").value;
var rotFlag = flag.replace(/[a-zA-Z]/g, function(c){return String.fromCharCode((c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26);});
if ("PyvragFvqrYbtvafNerRnfl@syner-ba.pbz" == rotFlag) {
alert("Correct flag!");
} else {
alert("Incorrect flag, rot again");
}
}
</script>
</body>
</html>

一个加密,懒得逆算法直接爆破算了,反正咱也看不懂js

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
import string
import execjs

jscode = """
function encry(c){return String.fromCharCode((c <= "Z" ? 90 : 122) >= (c = c.charCodeAt(0) + 13) ? c : c - 26);}
"""
jsc = execjs.compile(jscode)

out = "PyvragFvqrYbtvafNerRnfl@syner-ba.pbz"
table = string.printable
def encry(s:str):
return jsc.call("encry", s)

flag = []
for i in range(len(out)):
if out[i] in string.ascii_letters:
for letter in table:
if encry(letter) == out[i]:
flag.append(letter)
print(letter, end=' ')
break
else:
flag.append('_')
else:
flag.append(out[i])
print(''.join(flag))
print([ord(x) for x in flag])
print(len(out))
print(len(flag))

出flagClientSideLoginsAreEasy@flare-on.com,其中的S还被换成了9,后面猜了一下出了

V&N 2020 CSRe

是个.Net文件,放在dnspy下面跑一堆乱码,完全没法看,用de4dot看看

关键函数

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
using System;
using System.Security.Cryptography;
using System.Text;

// Token: 0x02000006 RID: 6
internal sealed class Class3
{
// Token: 0x0600000D RID: 13 RVA: 0x000022C8 File Offset: 0x000004C8
public string method_0(string string_0, string string_1)
{
string text = string.Empty;
char[] array = string_0.ToCharArray();
char[] array2 = string_1.ToCharArray();
int num = (array.Length < array2.Length) ? array.Length : array2.Length;
for (int i = 0; i < num; i++)
{
text += (int)(array[i] ^ array2[i]);
}
return text;
}

// Token: 0x0600000E RID: 14 RVA: 0x0000231C File Offset: 0x0000051C
public static string smethod_0(string string_0)
{
byte[] bytes = Encoding.UTF8.GetBytes(string_0);
byte[] array = SHA1.Create().ComputeHash(bytes);
StringBuilder stringBuilder = new StringBuilder();
foreach (byte b in array)
{
stringBuilder.Append(b.ToString("X2"));
}
return stringBuilder.ToString();
}

// Token: 0x0600000F RID: 15 RVA: 0x00002374 File Offset: 0x00000574
private static void Main(string[] args)
{
if (!Class1.smethod_1())
{
return;
}
bool flag = true;
Class3 @class = new Class3();
string str = Console.ReadLine();
if (Class3.smethod_0("3" + str + "9") != "B498BFA2498E21325D1178417BEA459EB2CD28F8")
{
flag = false;
}
string text = Console.ReadLine();
string string_ = Class3.smethod_0("re" + text);
string text2 = @class.method_0(string_, "63143B6F8007B98C53CA2149822777B3566F9241");
for (int i = 0; i < text2.Length; i++)
{
if (text2[i] != '0')
{
flag = false;
}
}
if (flag)
{
Console.WriteLine("flag{" + str + text + "}");
}
}
}

函数还是比较清楚,先查sha1B498BFA2498E21325D1178417BEA459EB2CD28F8,是314159

然后就是查被xor 之后的sha1 了,他这句text2[i] != '0'看的我很迷,然后就查原文,查到是return

所以flag就是flag{1415turn}

BJDCTF easy

打开一看

1
2
3
4
5
6
7
8
9
10
11
12
int __cdecl main(int argc, const char **argv, const char **envp)
{
time_t v4; // [esp+10h] [ebp-3F0h]
struct tm *v5; // [esp+3FCh] [ebp-4h]

__main();
time(&v4);
v5 = localtime(&v4);
puts("Can you find me?\n");
system("pause");
return 0;
}

???看了一下汇编也没啥玩意啊?

看了一下main函数上面那个有点蹊跷

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
int ques()
{
int v0; // edx
int result; // eax
int v2[50]; // [esp+20h] [ebp-128h]
int v3; // [esp+E8h] [ebp-60h]
int v4; // [esp+ECh] [ebp-5Ch]
int v5; // [esp+F0h] [ebp-58h]
int v6; // [esp+F4h] [ebp-54h]
int v7; // [esp+F8h] [ebp-50h]
int v8; // [esp+FCh] [ebp-4Ch]
int v9; // [esp+100h] [ebp-48h]
int v10; // [esp+104h] [ebp-44h]
int v11; // [esp+108h] [ebp-40h]
int v12; // [esp+10Ch] [ebp-3Ch]
int j; // [esp+114h] [ebp-34h]
__int64 v14; // [esp+118h] [ebp-30h]
int v15; // [esp+124h] [ebp-24h]
int v16; // [esp+128h] [ebp-20h]
int i; // [esp+12Ch] [ebp-1Ch]

v3 = 0x7FFA7E31;
v4 = 0x224FC;
v5 = 0x884A4239;
v6 = 0x22A84;
v7 = 0x84FF235;
v8 = 0x3FF87;
v9 = 0x88424233;
v10 = 0x23185;
v11 = 0x7E4243F1;
v12 = 0x231FC;
for ( i = 0; i <= 4; ++i )
{
memset(v2, 0, sizeof(v2));
v16 = 0;
v15 = 0;
v0 = *(&v4 + 2 * i);
LODWORD(v14) = *(&v3 + 2 * i);
HIDWORD(v14) = v0;
while ( SHIDWORD(v14) > 0 || v14 >= 0 && (_DWORD)v14 )
{
v2[v16++] = ((SHIDWORD(v14) >> 31) ^ (((unsigned __int8)(SHIDWORD(v14) >> 31) ^ (unsigned __int8)v14)
- (unsigned __int8)(SHIDWORD(v14) >> 31)) & 1)
- (SHIDWORD(v14) >> 31);
v14 /= 2LL;
}
for ( j = 50; j >= 0; --j )
{
if ( v2[j] )
{
if ( v2[j] == 1 )
{
putchar('*');
++v15;
}
}
else
{
putchar(' ');
++v15;
}
if ( !(v15 % 5) )
putchar(32);
}
result = putchar(10);
}
return result;
}

但是查找交叉引用缺啥也没有,改一下eip看看直接执行这个函数,执行结果是这个

1
2
3
4
5
6
7
8
9
10
*   *   *   ***** *   * ***** ***** * *   ***** *   * *   *
* * * * * * * * * * * * * * ** *
***** ***** * *** * * ***** *** * * * * *
* * * * * * ** * * * * * * * **
* * * * ***** * * ***** * * * ***** * *
* * * ***** * * ***** ***** * * ***** * * * *
* * * * * * * * * * * * * * ** *
***** ***** * *** * * ***** *** * * * * *
* * * * * * ** * * * * * * * **
* * * * ***** * * ***** * * * ***** * *

HACKIT4FUN,出了