Write-up - Insomni'hack 2011 - Reverse 2
by @Jonathan Salwan - 2011-03-06First, we check the file type
jonathan@ArchLinux [reverse] $ file server server: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped
Ok, it's classical linux/x86-32 bits binary.
Then, we create a file called key.txt for the same context than the CTF.
jonathan@ArchLinux [reverse] $ echo "Bravo, le flag est: xxxxx" >> key.txt jonathan@ArchLinux [reverse] $ cat key.txt Bravo, le flag est: xxxxx jonathan@ArchLinux [reverse] $
The binary calls the net_init function which initializes the socket. We reverse it for know what is the port listened.
gdb$ disass net_init Dump of assembler code for function net_init: [...] 0x08048aea <+138>: movw $0x2,-0x1c(%ebp) 0x08048af0 <+144>: mov 0x8(%ebp),%eax 0x08048af3 <+147>: movzwl %ax,%eax 0x08048af6 <+150>: mov %eax,(%esp) 0x08048af9 <+153>: call 0x80487e8 <htons@plt> 0x08048afe <+158>: mov %ax,-0x1a(%ebp) 0x08048b02 <+162>: movl $0x0,-0x18(%ebp) 0x08048b09 <+169>: movl $0x8,0x8(%esp) 0x08048b11 <+177>: movl $0x0,0x4(%esp) [...] gdb$ b *0x08048af9 Breakpoint 1 at 0x8048af9 gdb$ r [Thread debugging using libthread_db enabled] --------------------------------------------------------------------------[regs] EAX: 000022B8 EBX: B7F9CFF4 ECX: 00000004 EDX: 00000802 ESI: 00000000 EDI: 00000000 EBP: BFFFF7B8 ESP: BFFFF770 EIP: 08048AF9 --------------------------------------------------------------------------[code] => 0x8048af9 <net_init+153>: call 0x80487e8 <htons@plt> 0x8048afe <net_init+158>: mov %ax,-0x1a(%ebp) 0x8048b02 <net_init+162>: movl $0x0,-0x18(%ebp) 0x8048b09 <net_init+169>: movl $0x8,0x8(%esp) 0x8048b11 <net_init+177>: movl $0x0,0x4(%esp) 0x8048b19 <net_init+185>: lea -0x1c(%ebp),%eax 0x8048b1c <net_init+188>: add $0x8,%eax 0x8048b1f <net_init+191>: mov %eax,(%esp) -------------------------------------------------------------------------------- Breakpoint 1, 0x08048af9 in net_init () gdb$
EAX = 0x22b8. So, the port is 8888.
Another interesting function, talk_with_client. Let's reverse it.
gdb$ disass talk_with_client Dump of assembler code for function talk_with_client: 0x08048e93 <+0>: push %ebp 0x08048e94 <+1>: mov %esp,%ebp 0x08048e96 <+3>: sub $0x38,%esp 0x08048e99 <+6>: movl $0x0,-0x10(%ebp) 0x08048ea0 <+13>: movl $0x0,-0x18(%ebp) 0x08048ea7 <+20>: movl $0x0,-0x1c(%ebp) 0x08048eae <+27>: mov 0x8(%ebp),%eax 0x08048eb1 <+30>: mov (%eax),%eax 0x08048eb3 <+32>: mov %eax,-0xc(%ebp) 0x08048eb6 <+35>: movl $0x9,(%esp) 0x08048ebd <+42>: call 0x80488b8 <malloc@plt> 0x08048ec2 <+47>: mov %eax,-0x1c(%ebp) 0x08048ec5 <+50>: movl $0x9,0x8(%esp) 0x08048ecd <+58>: mov -0x1c(%ebp),%eax 0x08048ed0 <+61>: mov %eax,0x4(%esp) 0x08048ed4 <+65>: mov -0xc(%ebp),%eax 0x08048ed7 <+68>: mov %eax,(%esp) 0x08048eda <+71>: call 0x80487f8 <read@plt> 0x08048edf <+76>: mov %eax,-0x14(%ebp) 0x08048ee2 <+79>: cmpl $0x9,-0x14(%ebp) 0x08048ee6 <+83>: je 0x8048efe <talk_with_client+107> 0x08048ee8 <+85>: mov $0x80490cf,%eax 0x08048eed <+90>: mov -0x14(%ebp),%edx 0x08048ef0 <+93>: mov %edx,0x4(%esp) 0x08048ef4 <+97>: mov %eax,(%esp) 0x08048ef7 <+100>: call 0x8048878 <printf@plt> 0x08048efc <+105>: jmp 0x8048f65 <talk_with_client+210> 0x08048efe <+107>: mov -0x1c(%ebp),%eax 0x08048f01 <+110>: mov %eax,(%esp) 0x08048f04 <+113>: call 0x8048e27 <validate_input> 0x08048f09 <+118>: mov %eax,-0x10(%ebp) 0x08048f0c <+121>: cmpl $0x0,-0x10(%ebp) 0x08048f10 <+125>: je 0x8048f4f <talk_with_client+188> 0x08048f12 <+127>: call 0x8048d58 <read_key> 0x08048f17 <+132>: mov %eax,-0x18(%ebp) 0x08048f1a <+135>: cmpl $0x0,-0x18(%ebp) 0x08048f1e <+139>: je 0x8048f4f <talk_with_client+188> 0x08048f20 <+141>: mov -0x18(%ebp),%eax 0x08048f23 <+144>: mov %eax,(%esp) 0x08048f26 <+147>: call 0x8048858 <strlen@plt> 0x08048f2b <+152>: add $0x1,%eax 0x08048f2e <+155>: mov %eax,0x8(%esp) 0x08048f32 <+159>: mov -0x18(%ebp),%eax 0x08048f35 <+162>: mov %eax,0x4(%esp) 0x08048f39 <+166>: mov -0xc(%ebp),%eax 0x08048f3c <+169>: mov %eax,(%esp) 0x08048f3f <+172>: call 0x80487a8 <write@plt> 0x08048f44 <+177>: mov -0x18(%ebp),%eax 0x08048f47 <+180>: mov %eax,(%esp) 0x08048f4a <+183>: call 0x8048808 <free@plt> 0x08048f4f <+188>: mov -0x1c(%ebp),%eax 0x08048f52 <+191>: mov %eax,(%esp) 0x08048f55 <+194>: call 0x8048808 <free@plt> 0x08048f5a <+199>: mov -0xc(%ebp),%eax 0x08048f5d <+202>: mov %eax,(%esp) 0x08048f60 <+205>: call 0x80488a8 <close@plt> 0x08048f65 <+210>: leave 0x08048f66 <+211>: ret End of assembler dump. gdb$
This function calls two interesting functions:
- validate_input
- read_key
Let's reverse validate_input.
gdb$ disass validate_input Dump of assembler code for function validate_input: 0x08048e27 <+0>: push %ebp 0x08048e28 <+1>: mov %esp,%ebp 0x08048e2a <+3>: sub $0x10,%esp 0x08048e2d <+6>: mov 0x8(%ebp),%eax 0x08048e30 <+9>: movzbl (%eax),%eax 0x08048e33 <+12>: cmp $0x53,%al 0x08048e35 <+14>: je 0x8048e3e <validate_input+23> 0x08048e37 <+16>: mov $0x0,%eax 0x08048e3c <+21>: jmp 0x8048e91 <validate_input+106> 0x08048e3e <+23>: movl $0x0,-0x4(%ebp) 0x08048e45 <+30>: jmp 0x8048e86 <validate_input+95> 0x08048e47 <+32>: mov -0x4(%ebp),%eax 0x08048e4a <+35>: add 0x8(%ebp),%eax 0x08048e4d <+38>: movzbl (%eax),%eax 0x08048e50 <+41>: movsbl %al,%eax 0x08048e53 <+44>: movzbl %al,%ecx 0x08048e56 <+47>: mov -0x4(%ebp),%eax 0x08048e59 <+50>: add $0x1,%eax 0x08048e5c <+53>: add 0x8(%ebp),%eax 0x08048e5f <+56>: movzbl (%eax),%eax 0x08048e62 <+59>: movsbl %al,%edx 0x08048e65 <+62>: mov -0x4(%ebp),%eax 0x08048e68 <+65>: add $0x2,%eax 0x08048e6b <+68>: add 0x8(%ebp),%eax 0x08048e6e <+71>: movzbl (%eax),%eax 0x08048e71 <+74>: movsbl %al,%eax 0x08048e74 <+77>: lea (%edx,%eax,1),%eax 0x08048e77 <+80>: cmp %eax,%ecx 0x08048e79 <+82>: je 0x8048e82 <validate_input+91> 0x08048e7b <+84>: mov $0x0,%eax 0x08048e80 <+89>: jmp 0x8048e91 <validate_input+106> 0x08048e82 <+91>: addl $0x3,-0x4(%ebp) 0x08048e86 <+95>: cmpl $0x8,-0x4(%ebp) 0x08048e8a <+99>: jle 0x8048e47 <validate_input+32> 0x08048e8c <+101>: mov $0x1,%eax 0x08048e91 <+106>: leave 0x08048e92 <+107>: ret End of assembler dump. gdb$
Let's reverse it, step by step.
0x08048e2d <+6>: mov 0x8(%ebp),%eax 0x08048e30 <+9>: movzbl (%eax),%eax 0x08048e33 <+12>: cmp $0x53,%al
The function compares the first character by the 0x53 (S)
0x08048e37 <+16>: mov $0x0,%eax 0x08048e3c <+21>: jmp 0x8048e91 <validate_input+106>
If the first character isn't S we leave this function and return 0.
0x08048e3e <+23>: movl $0x0,-0x4(%ebp) 0x08048e45 <+30>: jmp 0x8048e86 <validate_input+95>
It initializes the i variable with value 0.
0x08048e86 <+95>: cmpl $0x8,-0x4(%ebp) 0x08048e8a <+99>: jle 0x8048e47 <validate_input+32>
And compares if the size of string is 0x08. So, the password has 9 characters.
0x08048e47 <+32>: mov -0x4(%ebp),%eax 0x08048e4a <+35>: add 0x8(%ebp),%eax 0x08048e4d <+38>: movzbl (%eax),%eax 0x08048e50 <+41>: movsbl %al,%eax 0x08048e53 <+44>: movzbl %al,%ecx 0x08048e56 <+47>: mov -0x4(%ebp),%eax 0x08048e59 <+50>: add $0x1,%eax 0x08048e5c <+53>: add 0x8(%ebp),%eax 0x08048e5f <+56>: movzbl (%eax),%eax 0x08048e62 <+59>: movsbl %al,%edx 0x08048e65 <+62>: mov -0x4(%ebp),%eax 0x08048e68 <+65>: add $0x2,%eax 0x08048e6b <+68>: add 0x8(%ebp),%eax 0x08048e6e <+71>: movzbl (%eax),%eax 0x08048e71 <+74>: movsbl %al,%eax 0x08048e74 <+77>: lea (%edx,%eax,1),%eax 0x08048e77 <+80>: cmp %eax,%ecx 0x08048e79 <+82>: je 0x8048e82 <validate_input+91> 0x08048e7b <+84>: mov $0x0,%eax 0x08048e80 <+89>: jmp 0x8048e91 <validate_input+106> 0x08048e82 <+91>: addl $0x3,-0x4(%ebp) 0x08048e86 <+95>: cmpl $0x8,-0x4(%ebp) 0x08048e8a <+99>: jle 0x8048e47 <validate_input+32>
This section adds the value of seconds character with the third character and comapres if it's equal to 0x53 ('S'). And repeats this scenario while i != 8.
So, our key is "S!2S!2S!2".
'!' + '2' = 0x21 + 0x32 = 0x53 = S
Now, let's test with the server.
jonathan@ArchLinux [write-up] $ cat connection.py #!/usr/bin/env python2 import socket s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) answer = s.recv(1024) print answer connect = s.connect(('192.168.0.3', 8888)) s.send("S!2S!2S!2") s.close jonathan@ArchLinux [write-up] $ ./connection.py Bravo, le flag est: xxxxx jonathan@ArchLinux [write-up] $