Last one
Src |
Date (GMT) |
Titre |
Description |
Tags |
Stories |
Notes |
|
2024-05-05 19:59:43 |
BSidesSF 2024 Writeups: Can\'t Give In (CGI exploitation) (lien direct) |
The premise of the three challenges cant-give-in, cant-give-in-secure, and cant-give-in-securer are to learn how to exploit and debug compiled code that\'s loaded as a CGI module. You might think that\'s unlikely, but a surprising number of enterprise applications (usually hardware stuff - firewalls, network “security” appliances, stuff like that) is powered by CGI scripts. You never know!
This challenge was inspired by one of my co-workers at GreyNoise asking how to debug a CGI script. I thought it\'d be cool to make a multi-challenge series in case others didn\'t know!
This write-up is intended to be fairly detailed, to help new players understand their first stack overflow!
Part 1: cant-give-in
The vulnerability
First, let\'s look at the vuln! All three challenges have pretty similar vulnerabilities, but here\'s what the first looks like:
char *strlength = getenv("CONTENT_LENGTH");
if(!strlength) {
printf("ERROR: Please send data!");
exit(0);
}
int length = atoi(strlength);
read(fileno(stdin), data, length);
if(!strcmp(data, "password=MyCoolPassword")) {
printf("SUCCESS: authenticated successfully!");
} else {
printf("ERROR: Login failed!");
}
The way CGI works - a fact that I\'d forgotten since learning Perl like 20 years ago - is that the headers are processed by Apache and sent to the script as environmental variables, and the body (ie, POST data) is sent on stdin.
In that script, we read the Content-Length from a variable, then read that many bytes of the POST body into a static buffer. That\'s a fairly standard buffer overflow, with the twist that it\'s in a CGI application!
We can demonstrate the issue pretty easily by running the CGI directly (I\'m using dd to produce 200 characters without cluttering up the screen):
|
Tool
Vulnerability
Threat
Technical
|
|
★★★★
|
|
2024-05-05 00:00:00 |
BSIDESSF 2024 Écritures: ne peut pas donner (exploitation CGI) BSidesSF 2024 Writeups: Can\\'t Give In (CGI exploitation) (lien direct) |
The premise of the three challenges cant-give-in, cant-give-in-secure, and cant-give-in-securer are to learn how to exploit and debug compiled code that\'s loaded as a CGI module. You might think that\'s unlikely, but a surprising number of enterprise applications (usually hardware stuff - firewalls, network “security” appliances, stuff like that) is powered by CGI scripts. You never know!
This challenge was inspired by one of my co-workers at GreyNoise asking how to debug a CGI script. I thought it\'d be cool to make a multi-challenge series in case others didn\'t know!
This write-up is intended to be fairly detailed, to help new players understand their first stack overflow!
Part 1: cant-give-in
The vulnerability
First, let\'s look at the vuln! All three challenges have pretty similar vulnerabilities, but here\'s what the first looks like:
char *strlength = getenv("CONTENT_LENGTH");
if(!strlength) {
printf("ERROR: Please send data!");
exit(0);
}
int length = atoi(strlength);
read(fileno(stdin), data, length);
if(!strcmp(data, "password=MyCoolPassword")) {
printf("SUCCESS: authenticated successfully!");
} else {
printf("ERROR: Login failed!");
}
The way CGI works - a fact that I\'d forgotten since learning Perl like 20 years ago - is that the headers are processed by Apache and sent to the script as environmental variables, and the body (ie, POST data) is sent on stdin.
In that script, we read the Content-Length from a variable, then read that many bytes of the POST body into a static buffer. That\'s a fairly standard buffer overflow, with the twist that it\'s in a CGI application!
We can demonstrate the issue pretty easily by running the CGI directly (I\'m using dd to produce 200 characters without cluttering up the screen):
|
Tool
Vulnerability
Threat
|
|
★★★
|
|
2023-04-24 00:08:44 |
BSIDESSF 2023 Rédactions: Sortez (Difficiel Inverse Engineering + Exploitation) BSidesSF 2023 Writeups: Get Out (difficult reverse engineering + exploitation) (lien direct) |
This is a write-up for three challenges:
getout1-warmup
getout2-gettoken
getout3-apply
They are somewhat difficult challenges where the player reverses a network
protocol, finds an authentication bypass, and performs a stack overflow to
ultimately get code execution. It also has a bit of thematic / story to it!
Writeup
Getout is based on a
research project
I did over the winter on Rocket Software\'s UniData application. UniData (and
other software they make) comes with a server called UniRPC, which functions
very similarly to getoutrpc.
My intention for the three parts of getout are:
Solving getout1-warmup requires understanding how the RPC protocol works,
which, as I said, is very similar to UniRPC
In getout2-gettoken, I emulated CVE-2023-28503 as best I could
In getout3-apply, I emulated CVE-2023-28502 but made it much, much harder to exploit
Let\'s take a look at each!
getout1-warmup
The warmup is largely about reverse engineering enough of the protocol to
implement it. You can find libgetout.rb in my solution, but the summary is
that:
You connect to the RPC service
You send messages to the server, which are basically just a header, then a
body comprised of a series of packed fields (integers, strings, etc)
The first message starts with an integer opcode:
Opcode 0 = “list services”
Opcode 1 = “execute a service”
Once a service is executed, a different binary takes over, which implements
its own sub-protocol (though the packet formats are the same)
For getout1-warmup, you just have to connect to the service and it immediately
sends you the flag. On the server, it looks like:
int main(int argc, char *argv[])
{
int s = atoi(argv[1]);
packet_body_t *response = packet_body_create_empty();
packet_body_add_int( |
Vulnerability
Prediction
|
|
★★
|
|
2023-04-24 00:08:44 |
BSIDESSF 2023 Écritures: Too-Latte (exploitation Java de difficulté moyenne) BSidesSF 2023 Writeups: too-latte (medium-difficulty Java exploitation) (lien direct) |
too-latte
is a challenge I wrote based on
CVE-2023-0669,
which is an unsafe deserialization vulnerability in Fortra\'s GoAnywhere MFT
software. I modeled all the vulnerable code off, as much as I could, that
codebase. It\'s obviously themed quite differently.
Write-up
If you use a tool like jadx to unpack the
servlets, you\'ll find, through some layers of indirection, this code in
TokenWorker.java (that operates on the token parameter):
public static String unbundle(String token, KeyConfig keyConfig) throws Exception {
token = token.substring(0, token.indexOf("$"));
return new String(decompress(verify(decrypt(decode(token.getBytes(StandardCharsets.UTF_8)), keyConfig.getVersion()), keyConfig)), StandardCharsets.UTF_8);
}
The decode function decodes the token parameter from Base64.
The decrypt function decrypts the token with a static key. The actual decryption
code is under several layers of indirection, because Java is Java, but the
TokenEncryptor class has a key, IV, and algorithm:
private static final byte[] IV = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 |
Tool
Vulnerability
|
|
★★
|
|
2023-04-24 00:08:44 |
BSIDESSF 2023 Écritures: White plat (réversion Java plus simple) BSidesSF 2023 Writeups: Flat White (simpler Java reversing) (lien direct) |
Ceci est un article pour Flat-White
et |
Vulnerability
|
|
★★★
|
|
2023-01-23 20:14:17 |
Blast from the Past: How Attackers Compromised Zimbra With a Patched Vulnerability (lien direct) |
Last year, I worked on a vulnerability in Zimbra
(CVE-2022-41352 - my
AttackerKB analysis for Rapid7)
that turned out to be a new(-ish) exploit path for a really old bug in cpio -
CVE-2015-1194. But that was patched in 2019, so what happened?
(I posted this as a tweet-thread awhile back, but I decided to flesh it out and
make it into a full blog post!)
cpio is an archive tool commonly used for system-level stuff (firmware images
and such). It can also extract other format, like .tar, which we'll use since
it's more familiar.
cpio has a flag (--no-absolute-filenames), off by default,
that purports to prevent writing files outside of the target directory. That's
handy when, for example, extracting untrusted files with Amavis
(like Zimbra does).
The problem is, symbolic links can point to absolute paths, and therefore, even
with --no-absolute-filenames, there was no safe way to extract an untrusted
archive (outside of using a chroot environment or something similar, which
they really ought to do).
Much later, in 2019, the cpio team released cpio version 2.13, which
includes a patch for
CVE-2015-1194,
with unit tests and everything.
Some (not all) modern OSes include the patched version of cpio, which should be
the end of the story, but it's not!
I'm currently writing this on Fedora 35, so let's try exploiting it. We can
confirm that the version of cpio installed with the OS is, indeed, the fixed
version:
ron@fedora ~ $ cpio --version
cpio (GNU cpio) 2.13
Copyright (C) 2017 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.
Written by Phil Nelson, David MacKenzie, John Oleynick,
and Sergey Poznyakoff.
That means that we shouldn't be able to use symlinks to write outside of the
target directory, so let's create a .tar file that includes a symlink and a
file written through that symlink (this is largely copied from
this mailing list post:
ron@fedora ~ $ mkdir cpiotest
ron@fedora ~ $ cd cpiotest
ron@fedora ~/cpiotest $ ln -s /tmp/ ./demo
ron@fedora ~/cpiotest $ echo 'hello' > demo/imafile
ron@fedora ~/cpiotest $ tar -cvf demo.tar demo demo/imafile
demo
demo/imafile
ron@fedora ~/cpiotest $ |
Tool
Vulnerability
|
APT 17
|
★★★★
|
|
2022-06-17 20:19:21 |
BSidesSF 2022 Writeups: Game-y Challenges (Turtle, Guessme) (lien direct) |
Hey folks,
This is my (Ron's / iagox86's) author writeups for the BSides San Francisco 2022 CTF. You can get the full source code for everything on github. Most have either a Dockerfile or instructions on how to run locally. Enjoy!
Here are the four BSidesSF CTF blogs:
shurdles1/2/3, loadit1/2/3, polyglot, and not-for-taking
mod_ctfauth, refreshing
turtle, guessme
loca, reallyprettymundane
Turtle
While discussing how we could appeal to current trends, I had the idea of making a challenge based on Wordle, called Turdle. My husband talked me out of "Turd", so we ended up with Turtle.
I could swear growing up that we had a "game" called E-Z-Logic in elementary school, on the Apple ]['s we had. It was a graphical version of the logo programming language. You could move the little turtle around, and had to navigate mazes. I tried and failed to find a reference to it, so it may never have existed.
Anyway, combining this mythical game and Wordle, I came up with an impossible Wordle clone: you move the turtle around, and have to match the directions/distances. The original "vulnerability" was supposed to be that you could submit future solutions, and I looked at using a broken RNG or something for future dates. But honestly, solving the current day was difficult enough that I really only had to do that. Ohwell. :)
The vulnerability was in the 2-digit dates used to calculate the path. If you rewind by exactly 100 years, the solution is the same. So you just have to get the solution for 1922, and there ya go! Solution is here.
Honestly, this challenge was like 5% writing a challenge, and 95% making it look pretty. I thought it was pretty cool, though. :)
Guessme
I had the idea that I wanted to make a challenge based on Base64 ambiguity. I've tweeted about it a couple times in the past year, because I thought it was interesting!
The idea of [guessme[(https://github.com/BSidesSF/ctf-2022-release/tree/main/guessme) is that you're given a list of "clues" (which mean nothing), and you have one chance to guess the solution, which is checked using an encrypted base64-encoded token that the user also gets. If you guess wrong, you're sent the answer and it "blacklists" the encrypted token so you can't guess again.
The problem is that base64 is ambiguous! Each base64 character represents six bits of binary data, so four base64 characters are 24 bits or three bytes. But five base64 characters represent 30 bits, or 3.5 bytes. Since you obviously can't have half of a byte, the last 4 bits are disregarded. If you change those bits, you can create a new encoding without changing the original data!
My solution naively increments the final character until it works. Not the cleanest solution, but it works eventually!
uity. I've tweeted about it a couple times in the past year, because I thought it was interesting!
The idea of guessme is that you're given a list of |
Vulnerability
|
|
★★★★
|
|
2022-06-17 20:19:18 |
BSidesSF 2022 Writeups: Apache Challenges (mod_ctfauth, refresh) (lien direct) |
Hey folks,
This is my (Ron's / iagox86's) author writeups for the BSides San Francisco 2022 CTF. You can get the full source code for everything on github. Most have either a Dockerfile or instructions on how to run locally. Enjoy!
Here are the four BSidesSF CTF blogs:
shurdles1/2/3, loadit1/2/3, polyglot, and not-for-taking
mod_ctfauth, refreshing
turtle, guessme
loca, reallyprettymundane
Refreshing - Reverse proxy mischief
The Refreshing challenge implements a reverse proxy that checks the query string for mischief, and attaches a header if it's bad. If the PHP application with a blatant vulnerability sees that header, it prints an error and does not render.
This was actually based entirely on CVE-2022-1388 (the name "Refreshing" is a nod to F5) - you can see my Rapid7 writeup on AttackerKB.
This was absolutely new to me when I worked on that vuln: the Connection HTTP header can remove headers when proxying. That means if you set Connection: Xyz while proxying through Apache, it will remove the header Xyz when forwarding. This worked out of the box on Apache! I initially tried Nginx, and it did not work there - not sure why, maybe they don't implement that header the same?
Anyway, to solve this, all you have to do is set the header Connection: X-Security-Danger on the request, then take advantage of the path traversal on the PHP site:
$ curl -H 'Connection: X-Security-Danger' 'http://refreshing-d7c0f337.challenges.bsidessf.net/index.php?file=../../../../../../../flag.txt'
CTF{press_f5_to_continue}
mod_ctfauth - A custom Apache authentication module
mod_ctfauth is a fairly simple Apache authentication plugin. It checks a username and token, then decides whether to grant access. I wrote it at the very last minute, because at work I was reverse engineering some Apache plugins and thought it'd be a good excuse to learn. And it worked! I've been re-using the container to test out more Apache stuff this week!
The source for the challenge is here. As you can see, it's really pretty straight forward - you can expect something more interesting next year, now that I know how these plugins work!
The bulk of the challenge is the following code (I removed a bunch of extra checks to shorten it down):
char *username = (char*)apr_table_get(r->headers_in, USERNAME_HEADER);
if(strcmp(username, "ctf")) {
return AUTHZ_DENIED;
}
char* header = (char*)apr_table_get( r->headers_in, HEADER);
char *encoded_token = header + strlen(TOKEN_PREFIX);
int actual_length = apr_base64_decode(decoded_token, encoded_token);
[...]
apr_md5_ctx_t md5;
apr_md5_init(&md5);
apr_md5_update(&md5, SECRET, strlen(SECRET));
apr_md5_update(&md5, username, strlen(username));
apr_md5_update(&md5, SECRET, strlen(SECRET));
char buffer[HASH_LENGTH];
apr_md5_final(buffer, &md5);
if(memcmp(buffe |
Vulnerability
|
|
★★★★
|
|
2021-03-18 17:07:36 |
BSidesSF CTF 2021 Author writeup: glitter-printer, a buffer underflow where you modify the actual code (lien direct) |
Hi Everybody!
This is going to be a challenge-author writeup for the Glitter Printer challenge from BSides San Francisco 2021.
First, a bit of history: the original idea I had behind Glitter Printer was to make a video game challenge involving cartridge-swap, where I'd write a handful of simple video games in 100% x86 code with no imports or anything (like an old fashioned cartridge game), and the player could swap between them without memory being re-initialized. Folks used to do this sorta thing on NES, and maybe I'll use it in a future challenge, but I decided to make this a bit simpler.
While experimenting with writing libraries without libc, I realized just how much work it was going to be to write a bunch of games, and decided to simplify. My next ide was to write a “driver” type thing, where a blob of code is loaded into +RWX memory and the player could go wild on it. The the name Glitter Printer came across my radar, I don't even remember why, and that gave me the idea to do an LPR server.
That's quite the background!
The code
So I don't know if anybody actually noticed, but I implemented a good chunk of the Line Printer (LPR) RFC correctly. Well, I tried to anyways, I didn't actually test it with a real client. The hard part was introducing a realistic-looking vulnerability - in many of my CTF challenges, the vuln comes naturally. So naturally, in fact, that I often don't even need to plan it in advance! I ended up settling on an integer underflow.
If you look at the source (specifically, core.c), you can see that the main loop reads a single byte, then performs an action accordingly:
void _start(queue_t *queues) {
while(1) {
char command = read_byte(STDIN);
if(command == 1) {
print_waiting_jobs();
} else if(command == 2) {
receive_job(queues);
} else if(command == 3) {
queue_state_list(queues, 0);
} else if(command == 4) {
queue_state_list(queues, 1);
} else if(command == 5) {
// 05 Queue SP Agent SP List LF - Remove jobs
} else {
exit(6);
}
}
}
As part of several commands (such as receive_job()), an ASCII number is sent to choose a queue to operate on. The queue number isn't a byte (like “\x01”), it's a number like “123” that needs to be parsed.
And by the way, this is still how LPR actually works!
Here's the code I used for parsing numbers.. I'm pretty sure I just grabbed this from Stack Overflow:
int read_number(char *terminator) {
int result = 0;
while(1) {
// Read a single byte
char buffer = read_byte();
// If it's not a valid byte, we're done (and we consume the terminator)
if(buffer < '0' || buffer > '9') {
|
Vulnerability
Guideline
|
|
★★★★
|
|