Article directory
Experimental requirements
Change printf
the function to a new newprintf
function, getshell
and execute the following instructions:
whoami
echo "学号" > num.txt
cat num.txt
exit
/bin/sh
The string is the parameter in , getshell
so printf
this can be used directly.
experiment procedure
The experimental principle I adopted: copy the patch program .text
to the target program .eh_frame
, and then modify the function jump address of the target program to make the vulnerable program jump .eh_frame
to execute the patch code.
1. Write a new printf function
I use inline assembly. The syntax used by inline assembly is AT&T
. It is different from the compilation that is usually written Intel
. For the writing of inline assembly, I refer to this short book: GCC Inline Assembly Basics - Short Book (jianshu.com) .
Thanks again for the blogger's detailed explanation!
The code written hook.c
is as follows:
void myprintf(char *a, int b) {
int tmp;
asm(
"mov %1,%%rdi\n"
:"=r"(tmp)
:"r"(a)
:"%rdi"
);
asm(
"mov $0,%rsi\n"
"mov $0,%rdx\n"
"mov $59,%rax\n"
"syscall\n"
);
}
The main meaning is that the constructor execve(a,0,0)
, where a
is the original printf
parameter /bin/sh
. execve
Corresponds to the system call number on a 64-bit system 59
.
Compile the above code into a static link library:
gcc -c hook.c -o hook
2. Write a Python script that uses LIEF
First install dependencies:
pip install lief -y
pip install pwn -y
Note:
-y
The parameter is the default when the "whether to install" pops upyes
. The lower version of pip does not support this option, so don't add it. Personally, I am used to adding-y
parameters.
When downloading the lief of python2, an error is always reported. lief
Checked on the official So the python3 environment is used.
If you use python2, just copy the instruction book script directly.
The idea of the script is the same as that in the instruction book: read and parse the file, getshell
copy the section to the section, and modify the statement to . Finally, write the modified executable to .hook
hook
.text
getshell
.eh_frame
call _printf
call .eh_frame的起始地址
getshell.patched
Only due to python
version issues, there are 3 places that need to be modified:
- The output of python3
print
needs brackets; bytes
The two data types are distinguished in python3string
, but mixed in python2, so it needs to be added before the byte string in python3b
to splice with the p32 conversion result.ord()
The type accepted by this function is a string with a length of 1. Whenfor...in...
traversingbytes
the type, the obtainedint
data is already the type. It is necessary to callord
it in python2, but it does not need to be called in python3.
The specific script lief_test.py
is as follows:
import lief
from pwn import *
def patch_call(file,srcaddr, dstaddr , arch = "amd64"):
print(hex(dstaddr))
length = p32((dstaddr - (srcaddr + 5 ))& 0xffffffff)
order = b'\xe8' +length
print(disasm(order , arch=arch))
file.patch_address(srcaddr, [i for i in order])
binary = lief.parse("./getshell")
hook = lief.parse('./hook')
# write hook 's .text content to binary's .eh_frame content
sec_ehrame = binary.get_section( '.eh_frame')
print(sec_ehrame.content)
sec_text = hook.get_section('.text')
print(sec_text.content)
sec_ehrame.content = sec_text.content
print(binary.get_section('.eh_frame').content)
# hook target call
dstaddr = sec_ehrame.virtual_address
srcaddr = 0x401149
patch_call(binary,srcaddr,dstaddr)
binary.write('getshell.patched')
3. Set getshell
the .eh_frame
section as executable
Directly modify .eh_frame
the section and jump to execute, the following segment error will be reported:
Change permissions: Segment fault|Modify ELF non-executable segment permissions (010 editor) .
That's fine.
4. Apply the patch and run the patched program
Compile the patch, apply the patch, and run the patched program:
gcc -c hook.c -o hook
python3 lief_test.py
./getshell.patched
Finally, verify that the fetch was successful shell
.
enter:
whoami
echo "学号" > num.txt
cat num.txt
exit
It can be seen that the shell can be obtained successfully.
5. Ensure that the size of the program remains unchanged before and after modification
After discussing with my classmates, I found that the size of the program has changed greatly, mainly due to LIEF
the limitations of this library. This patch is really very simple, so I decided IDA Pro
to use for patching to ensure that the program size remains the same before and after modification. ( I don't know if it works, but I really don't know how to do it otherwise )
The principle is the same as the previous assignment overflow
. For details, see this HUST network attack and defense practice|5_Binary file patch technology|Experiment 1 overflow .
I wrote sloppily, and some seniors wrote better ones, and I found it after a search:
[Network Security Practice III] Experiment 5. Patch
Change call _printf
it to jmp 0x402058
, which is .eh_frame
the starting position to jump to. Then .eh_frame
write the patch code, the patch code finally jumps back to the original execution flow:
mov rsi,0
mov rdx,0
mov rax,59
syscall
jmp 0x40114E
Then change the section where the original program .eh_frame
is located to be executable.
The result of the operation is as follows. It can be seen that it was getshell
successful without changing the file size.