I'm new to security and currently referring to Robert Seacord's Secure Coding in C and C++.
In chapter 2 of the same, the author talks about arc injection, wherein he passes the flow of control in the following program from the isPasswordOK()
routine to the else() {puts ("Access granted!");};
branch in main()
by overwriting the Password
buffer in gets()
call with a tainted string: 1234567890123456j>*!
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
bool isPasswordOK(void) {
char Password[12];
gets(Password);
return 0 == strcmp(Password, "goodpass");
}
int main(void) {
bool pwStatus;
puts("Enter Password: ");
pwStatus = isPasswordOK();
if (pwStatus == false) {
puts("Access denied");
exit(-1);
}
else {
puts("Access granted!");
}
}
Here, j = 0x6A
, > = 0x10
(This is the Data Link Escape symbol), * = 0x2A
and ! = 0x21
This sequence of 4 characters then corresponds to a 4-byte address, which I'm assuming is 0x6A102A21
. This address, I think, points to the else
line in the main()
function, and we redirect control by overwriting the return address on the stack by the address of this line.
I'm trying to reproduce the same on my machine (x86-64 architecture). I've turned stack protection and randomization off, so I don't think that should be a issue. In fact, the program crashes as expected when I try to corrupt the return address. My problem is: how do I provide as an input to gets
the tainted string? If I disassemble main
using gdb, I get the following output:
(gdb) disassemble main
Dump of assembler code for function main:
0x0000000000400642 <+0>: push %rbp
0x0000000000400643 <+1>: mov %rsp,%rbp
0x0000000000400646 <+4>: sub $0x10,%rsp
0x000000000040064a <+8>: mov $0x40071d,%edi
0x000000000040064f <+13>: callq 0x4004c0 <puts@plt>
0x0000000000400654 <+18>: callq 0x400616 <isPasswordOK>
0x0000000000400659 <+23>: mov %al,-0x1(%rbp)
0x000000000040065c <+26>: movzbl -0x1(%rbp),%eax
0x0000000000400660 <+30>: xor $0x1,%eax
0x0000000000400663 <+33>: test %al,%al
0x0000000000400665 <+35>: je 0x40067b <main+57>
0x0000000000400667 <+37>: mov $0x40072e,%edi
0x000000000040066c <+42>: callq 0x4004c0 <puts@plt>
0x0000000000400671 <+47>: mov $0xffffffff,%edi
0x0000000000400676 <+52>: callq 0x400510 <exit@plt>
0x000000000040067b <+57>: mov $0x40073c,%edi
0x0000000000400680 <+62>: callq 0x4004c0 <puts@plt>
0x0000000000400685 <+67>: leaveq
0x0000000000400686 <+68>: retq
End of assembler dump.
Since I want to jump to the second puts()
call, I think I need to provide 0x0000000000400680
as a part of my tainted string because this is the address of the second puts()
according to the gdb disassembly.
How can I do this? In the book, the address was of length 8, but here I have one of length 16. Also, there is no ASCII representation for 0x80
, so what am I supposed to provide as an input to gets
? Basically, what I'm asking for are the characters that I should provide at ?:
1234567890123456????