Skip to content

Commit

Permalink
Merge branch 'main' of github.com:Pwnzer0tt1/pwnzer0tt1.it
Browse files Browse the repository at this point in the history
  • Loading branch information
domysh committed Sep 8, 2023
2 parents d188c8d + 424d1ba commit 3799579
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 2 deletions.
2 changes: 1 addition & 1 deletion content/about/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Our team was born during the national competition of [CyberChallenge](https://cy

Here you can find some information about the participants of the team:
{{< cardbox >}}
{{< card img="imgs/domysh.jpg" title="Domingo Dirutigliano" github="https://github.com/domysh" website="https://domysh.com" email="me@domysh.com">}}
{{< card img="imgs/domysh.jpg" title="Domingo Dirutigliano" github="https://github.com/domysh" website="https://domy.sh" email="me@domy.sh">}}
{{< card img="imgs/panic.jpg" title="Nicola Pace" github="https://github.com/nicolapace">}}
{{< card img="imgs/nicolag.png" title="Nicola Guerrera" github="https://github.com/nik012003" website="https://catboy.it" >}}
{{< card img="imgs/oscar.jpg" title="Oscar Urselli" github="https://github.com/oscar0urselli">}}
Expand Down
143 changes: 143 additions & 0 deletions content/posts/aush.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
+++
title = "zer0pts 2023: Aush (pwn, easy)"
author = "Domingo Dirutigliano"
tags = ["pwn"]
date = "2023-07-15"
+++
## Aush (pwn, easy)

>I will give you the shell, but after you authenticated yourself.
I spent a lot of time on this challenge because I typically focus on static analysis and don't execute the program until I understand how it works. Initially, I solved it without fully understanding the exploit, but after further analysis, I finally grasped its mechanism and wrote this write-up.

## Overview

The challenge provides us with the binary (also running on a remote server) and its C source code.

The program initially reads some bytes from `/dev/urandom`, which serve as the username and password. We need to input the correct values to obtain a shell.

One noteworthy aspect is that the binary uses cowsay to print messages (through `execve`).

```c
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define LEN_USER 0x10
#define LEN_PASS 0x20

int setup(char *passbuf, size_t passlen, char *userbuf, size_t userlen) {
int ret, fd;

// TODO: change it to password/username file
if ((fd = open("/dev/urandom", O_RDONLY)) == -1)
return 1;
ret = read(fd, passbuf, passlen) != passlen;
ret |= read(fd, userbuf, userlen) != userlen;
close(fd);
return ret;
}

int main(int argc, char **argv, char **envp) {
char *args[3];
char inpuser[LEN_USER+1] = { 0 };
char inppass[LEN_PASS+1] = { 0 };
char username[LEN_USER] = { 0 };
char password[LEN_PASS] = { 0 };

if (system("/usr/games/cowsay Welcome to AUSH: AUthenticated SHell!") != 0) {
write(STDOUT_FILENO, "cowsay not found\n", 17);
return 1;
}

/* Load password and username file */
if (setup(password, LEN_PASS, username, LEN_USER))
return 1;

/* Check username */
write(STDOUT_FILENO, "Username: ", 10);
if (read(STDIN_FILENO, inpuser, 0x200) <= 0)
return 1;

if (memcmp(username, inpuser, LEN_USER) != 0) {
args[0] = "/usr/games/cowsay";
args[1] = "Invalid username";
args[2] = NULL;
execve(args[0], args, envp);
}

/* Check password */
write(STDOUT_FILENO, "Password: ", 10);
if (read(STDIN_FILENO, inppass, 0x200) <= 0)
return 1;

if (memcmp(password, inppass, LEN_PASS) != 0) {
args[0] = "/usr/games/cowsay";
args[1] = "Invalid password";
args[2] = NULL;
execve(args[0], args, envp);
}

/* Grant access */
args[0] = "/bin/sh";
args[1] = NULL;
execve(args[0], args, envp);
return 0;
}
```
## My first doubts
There is a buffer overflow on the user input, but:
- The binary has PIE enabled, and there's no way to leak addresses.
- The binary has NX enabled, and there's no way to execute shellcode.
- The variable holding the random username is located below the user input buffer, which means we can't overwrite it using the buffer overflow.
So, The challenge is impossible?
However, it's labeled as an easy challenge. So, after overthinking it, I tried executing it by inputting a different size of "A" characters.
With 411 "A" characters as the username, it resulted in the correct username... What? How is it possible?
However, when I entered the overwritten password containing "A" characters, it seemed to pass the equality check, but no shell was spawned, and a stack smash was triggered.
## The brutal solution
After some debugging, I noticed that the `execve` for the shell was executed, but the pointer to the environment variables (`envp`) was partially overwritten, making it an invalid pointer. I tried overwriting it with zeros in the first input, but it didn't work. However, when I did the same using the second input, it worked! I got a shell!
```python
from pwn import *
p = process("./aush")
p.sendline(b"A"*411)
p.sendline(b"A"0x20+b"\x00"*400)
p.iteractive()
```

## Why it works?

The fact that it worked triggered my obsessive side for static analysis, so I tried to understand why it worked.

Using gdb and inserting the input `"A"*411`, I observed that the `memcmp` function was executed and returned `0xffffffff`, which is different from 0. Thus, the `execve` was executed... or was it?

And that's the point! The `execve` was executed, but it failed.

Thanks to our overflow, we reached the `envp` pointer on the stack and overwrote it, making it an invalid address.

While `execve` was indeed executed, the `envp` pointer was invalid, causing `execve` to fail. However, the program continued its execution without being interrupted by the `"error"` because the `cowsay binary` was used to close the main program. This is because it calls `exit_group` at the end, which kills the main program as well.

The first step of the exploit is to overwrite the `envp` pointer with an invalid value, so `execve` will be skipped. Additionally, we overwrite the generated password with a password of our choice.

Now we can pass the next check by inserting the chosen password. But there's a problem: at this point, `execve` is used to spawn our shell, but the `envp` pointer is still invalid, causing `execve` to fail, and no shell is spawned. D:

Now we need to enable again the execution of `execve`, and one way to do that is by using a `null pointer` instead of the `envp` pointer (execve accepts a null pointer as valid for environment).

So, we can insert the correct password chosen by us, but also overwrite the `envp` pointer with a null pointer. This way, cowsay will be skipped because the password is deemed correct, and execve will be able to spawn the shell normally.

---

## TL; DR

The challenge was easy to solve but tricky to understand.

I understood also that: `dynamic analysis >>> static analysis` :D
2 changes: 1 addition & 1 deletion hugo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ theme = 'paper'
twitter = 'https://twitter.com/pwnzer0tt1'
github = 'https://github.com/pwnzer0tt1'
#instagram = 'https://instagram.com/pwnzer0tt1'
discord = 'https://discord.gg/79NNVJBK5Z'
discord = 'https://discord.gg/NWyJydmRSg'
# home page profile
avatar = 'https://pwnzer0tt1.it/icon.png'
name = 'Pwnzer0tt1'
Expand Down

0 comments on commit 3799579

Please sign in to comment.