I try to exploit sprintf c function in my program which is used like this:
char line[512];
sprintf(line,"[%s]", UserCommand);
As you can see the line can be exploited and trigger something else. I found how to change rbp register but when it comes to RIP register, I can change it with "0xFFFF7FFFEBFF8C10" but I couldn't with "0x00007FFFEBFF8C10", the first 2 bytes "00 00" are replaced with 0x2D5D ( ]) which becomes 0x2D5D7FFFEBFF8C10. This address cannot lead me to my buffer where my arbitrary code reside.
The stack $rsp-100:
0x7fffebff8d94: 0xd23148f6 0x3bc08348 0xebe8050f 0x2fffffff
0x7fffebff8da4: 0x2f6e6962 0x4168732f 0x41414141 0x41414141
0x7fffebff8db4: 0x41414141 0x41414141 0x41414141 0x41414141
0x7fffebff8dc4: 0x41414141 0x41414141 0x41414141 0x41414141
0x7fffebff8dd4: 0x41414141 0x41414141 0x41414141 0x41414141
0x7fffebff8de4: 0xffffffff 0x41414141 0x0000155a 0x41414141
0x7fffebff8df4: 0x41414141 0xebff8c10 0x205d7fff 0x00000000
0x7fffebff8e04: 0x00000000 0x00bd5760 0x00000000 0x00000000
Backtrace in gdb:
0 0x00000000004093a0 in ProcessCmd (Ctx=40, Connect=27, Msg=0x7fffebff9e32 '\220' <repeats 200 times>..., Len=522)
at /home/sam/srv/cmd/proc.c:305
1 0x205d7fffebff8c10 in ?? ()
2 0x0000000000000000 in ?? ()
Register:
info r
rax 0xffffffff 4294967295
rbx 0x7fffebfff700 140737152808704
rcx 0x7ffff78cb1fd 140737346580989
rdx 0x919f40 9543488
rsi 0x0 0
rdi 0x919f40 9543488
rbp 0x4141414141414141 0x4141414141414141
rsp 0x7fffebff8df8 0x7fffebff8df8
r8 0x0 0
r9 0x29 41
r10 0x11 17
r11 0x0 0
r12 0x1 1
r13 0x7fffebfff9c0 140737152809408
r14 0x7fffebfff700 140737152808704
r15 0x0 0
rip 0x4093a0 0x4093a0 <ProcessCmd+407>
eflags 0x10202 [ IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
I want to know if this can be exploited or not ?
Is there any way to have a valid canonical address in the RIP register and remove the 2 bytes that making my address invalid ?
Thanks in advance
sprintf(line,"[%s] ", UserCommand);
, sprintf
will write '['
to line
, then your input which is NULL terminated string
, then ']'
, ' '
, and last NULL terminator
. Suppose you enter the string containing the shellcode and end with a return address. As you know that %s
format speicfier will STOP writing this input when it finds a NULL byte
.
Case 1:
Non_NULL_Shellcode = Your_shellcode
Return_address = 0xFFFF7FFFEBFF8C10
As you can see, no NULL byte in your input. So sprintf
will write '['
to line
, then your input which is NULL terminated string
containing shellcode and complete return address, then ']'
, ' '
, and last NULL terminator
. It works well.
Case 2:
Non_NULL_Shellcode = Your_shellcode
Return_address = 0x00007FFFEBFF8C10
What is the difference? Yes, your return address containing two NULL byte
at the end, which is interpreted by sprintf
as a marker to STOP writing from your input. So this will happen. sprintf
will write '['
to line
, then your input which is NULL terminated string
containing shellcode and incomplete return address, then ']'
, ' '
, and last NULL terminator
. ']' == 0x5d
and ' ' == 0x20
in ascii. When writing your return address (suppose in little endian) sprintf
will write 0x10
, 0x8C
, 0xFF
, 0xEB
, 0xFF
, 0x7F
and continue write 0x5D
, 0x20
, and last 0x00
which is NULL terminator
. So it explain why your address 0x00007FFFEBFF8C10 changes to 0x205D7FFFEBFF8C10. 0x205D is not garbage data it's your string. Hope it helpful :).