we expect a high standard of professionalism from you at all times while you are taking any of our courses. We expect all students to act in good faith at all times
TLDR: Don’t be a dick jerk
it’s not just syscalls for execve("/bin/sh", NULL, NULL)
malloc, printf, mmap can all leverage other exploits
write-what-where gadgets
mov [register1], register2
we can still use the stack to store stuff
mov rax, esp
sub rax, 10
mov rbx, rax
not just mov (add, mul, push, xchg?)
my buffer is too small
we can’t get a full payload
think back to egghunters in shellcode
a.k.a we
pivot the stack
vuln(){
char buff[16];
fgets(buff,24,stdin);
}
here, we only have enough room to overwrite a single address
[ XXXXXXXX ] *we cannot write here*
[ GADGET ] <- stored return pointer
[ AAAAAAAA ] <- stored frame pointer
[ AAAAAAAA ] <- padding
[ AAAAAAAA ]
[ AAAAAAAA ]
[ AAAAAAAA ]
we can overwrite the return address, but can only execute one instruction?
GADGET_1
= sub rsp, 48
[ GADGET_1 ] <- rsp points here
[ AAAAAAAA ]
[ AAAAAAAA ]
[ AAAAAAAA ]
[ AAAAAAAA ]
[ AAAAAAAA ]
[ GADGET_2 ] <- start of our payload
GADGET_1 gets invoked
gadget moves rsp to point at the start of our payload
[ GADGET_1 ]
[ AAAAAAAA ]
[ AAAAAAAA ]
[ AAAAAAAA ]
[ AAAAAAAA ]
[ AAAAAAAA ]
[ GADGET_2 ] <- rsp points here
so put our ROPChain as our “padding”
[ GADGET_1 ] <- ESP points here
[ GADGET_8 ] <- int 0x80
[ GADGET_7 ] <- xor esi, esi; ret
[ GADGET_5 ] <- xor edx, edx; ret
[ GADGET_4 ] <- mov ecx, 0x12345678; ret
[ GADGET_3 ] <- mov ebx, 0x12345678; ret
[ GADGET_2 ] <- mov eax, 11; ret
it could be the same buffer or another one
int vuln() {
char buffer[100];
fgets(buffer, 101, stdin);
return 0;
}
how2exploit?
why is this vulnerable?
int vuln(char *s) {
char buffer[100];
memset(buffer, 0, sizeof(buffer));
strncat(buffer, s, sizeof(buffer));
return 0;
}
these should be sizeof(buffer) - 1
int vuln(char *s) {
char buffer[100];
// vvvvvvvvvvvvvv
memset(buffer, 0, sizeof(buffer));
strncat(buffer, s, sizeof(buffer));
// ^^^^^^^^^^^^^^
return 0;
}
its only one byte
0xFFFF [ ABCDEFGH ] <- stored EIP
0xFFFC [ FFFFFFFF ] <- stored EBP
0xFFF8 [ AAAAAAAA ]
0xFFF4 [ AAAAAAAA ]
0xFFF0 [ AAAAAAAA ]
what do leave and ret do?
leave:
mov rsp, rbp // rsp = rbp
pop rbp // rbp = old_rbp
ret:
pop rax // rax = stored_rip
call rax // jump rax
overflow into least significant byte
0xFFFF [ ABCDEFGH ]
0xFFFC [ FFFFFFF0 ] <- partial overwrite
0xFFF8 [ AAAAAAAA ]
0xFFF4 [ AAAAAAAA ]
0xFFF0 [ AAAAAAAA ]
once we leave, ESP points to
0xFFF0
0xFFFF [ ABCDEFGH ]
0xFFFC [ FFFFFFF0 ]
0xFFF8 [ AAAAAAAA ]
0xFFF4 [ AAAAAAAA ]
0xFFF0 [ AAAAAAAA ] <- rsp points here (execution resumes here)
sig-return oriented programming
how kernel returns execution to program after signal
when a signal is invoked, the context (e.g. registers) are all pushed to the stack
the signal-handler may modify them, etc
these values are restored using sigreturn (a syscall)
we fake a sigreturn
sigreturn restores the values of registers based on content stored on the stack (we control the stack)
what if we pushed our own fake “context” (register values) onto the stack, and triggerd a sigreturn?
we could control all of the register values?
need help?
any content you want covered?
any challenges you want me to demo?