【HUST】Network Attack and Defense Practice|5_Binary File Patch Technology|Experiment 2 getshell

Experimental requirements

Change printfthe function to a new newprintffunction, getshelland execute the following instructions:

whoami
echo "学号" > num.txt
cat num.txt
exit

/bin/shThe string is the parameter in , getshellso printfthis can be used directly.

experiment procedure

The experimental principle I adopted: copy the patch program .textto the target program .eh_frame, and then modify the function jump address of the target program to make the vulnerable program jump .eh_frameto 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.cis 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 ais the original printfparameter /bin/sh. execveCorresponds 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: -yThe parameter is the default when the "whether to install" pops up yes. The lower version of pip does not support this option, so don't add it. Personally, I am used to adding -yparameters.

When downloading the lief of python2, an error is always reported. liefChecked 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, getshellcopy the section to the section, and modify the statement to . Finally, write the modified executable to .hookhook.textgetshell.eh_framecall _printfcall .eh_frame的起始地址getshell.patched

Only due to pythonversion issues, there are 3 places that need to be modified:

  1. The output of python3 printneeds brackets;
  2. bytesThe two data types are distinguished in python3 string, but mixed in python2, so it needs to be added before the byte string in python3 bto splice with the p32 conversion result.
  3. ord()The type accepted by this function is a string with a length of 1. When for...in...traversing bytesthe type, the obtained intdata is already the type. It is necessary to call ordit in python2, but it does not need to be called in python3.

The specific script lief_test.pyis 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 getshellthe .eh_framesection as executable

Directly modify .eh_framethe 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 LIEFthe limitations of this library. This patch is really very simple, so I decided IDA Proto 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 _printfit to jmp 0x402058, which is .eh_framethe starting position to jump to. Then .eh_framewrite 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_frameis located to be executable.
The result of the operation is as follows. It can be seen that it was getshellsuccessful without changing the file size.

Guess you like

Origin blog.csdn.net/qq_46106285/article/details/125098087