中国科学技术大学第五届信息安全大赛 —— USTC Hackergame 2018 WriteUp

[db:作者] 2021年11月29日17:54:14评论98 views字数 14953阅读49分50秒阅读模式
摘要

[db:摘要]

比赛入口地址:http://hack.lug.ustc.edu.cn/

题目存档:https://hack2018.lug.ustc.edu.cn/

官方 Writeup:https://github.com/ustclug/hackergame2018-writeups

第二年参加中科大的 Hackergame,今年多了许多大佬参加。

题目共 32 题,只解出 20 题。

比赛最终得分:3650;总排名:13;参赛组:其他;组内排名:11。

题外话

去贵阳玩了四天,在外面用手机把前面的 12 道题做出来了。

然后 MC 手机没法玩,还通宵去网咖玩 MC 把题做出来。

签到题 (Solved, 50pt)

直接访问 /?key=hackergame2018 ,就能得到 Flag。

Flag:flag{Hackergame2018_Have_Fun!}

猫咪问答 (Solved, 100pt)

社工题,上网找答案吧。

1. 1958
出处:百度百科
2. 9211B026
出处:网上搜索“中国科大学号的演变史”
3. 9
出处:手工爆破一下
4. TP311.1/94
出处:中国科技大学图书馆网站
5. 3A202
出处:LUG@USTC官网 LUG活动 栏目

Flag:flag{G00G1E-is-always-YOUR-FRIEND}

游园会的集章卡片 (Solved, 100pt)

拼图题,在手机上拼一下就好了。

Flag:flag{H4PPY_1M4GE_PR0CE551NG}

猫咪和键盘 (Solved, 150pt)

cpp 里面的代码顺序被破坏了,找规律,写个脚本重新排一下。

lines=open('typed_printf.cpp','r').readlines()
for line in lines:
    print line[0]+line[32:39]+line[1:7]+line[20:22]+line[8:20]+line[22:32]+line[39:-1]

观察一下代码就可以直接出 Flag

Flag:flag{FfQ47if9Zxw9jXE68VtGAJDk6Y6Xc88UrUtpK3iF8p7BMs4y2gzdG8Ao2gv6aiJ125typed_printf95}

Word 文档 (Solved, 150pt)

docx 格式,直接 zip 解压,就看到 flag.txt 文件了

Flag:flag{xlsx,pptx,docx_are_just_zip_files}

猫咪银行 (Solved, 150pt)

以为是“货币兑换”有漏洞,后来发现没什么问题。

然后尝试“买入分钟”改得很大,“取出时间”的年份异常大或者异常小,就感觉像是溢出。

换了几个数字,多试几遍,成功买到了 Flag。

正确操作流程:
用 CTB 兑换 6606 个 TDSU
买入理财产品。买入分钟:2333333333333333333;买入份额:1000
取出理财产品
用 TDSU 兑换 20 个 CTB
购买 FLAG

Flag:flag{Evil_Integer._Evil_Overflow.}

黑曜石浏览器 (Solved, 150pt)

访问黑曜石浏览器官网:https://heicore.com/

在官网网页源代码里找到 黑曜石浏览器 的 User-Agent:

Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) HEICORE/49.1.2623.213 Safari/537.36

直接在手机上用 curl 加上 User-Agent 去访问题目链接,就能得到 Flag。

Flag:flag{H3ic0re_49.1.2623.213_sai_kou}

回到过去 (Solved, 150pt)

题目给出键盘记录,直接复现一下就能看到 Flag。

Flag:flag{t4a2b8c44039f93345a3d9b2}

我是谁 (450pt)

哲学思考 (Solved, 150pt)

直接在手机上用 curl,看 HTTP 请求里的 Status Code,就得到答案:TEAPOT。

提交答案得到 Flag

Flag:flag{i_canN0t_BReW_c0ffEE!}

Can I help me? (Solved, 300pt)

根据 brew coffee 提示,找到 HTCPCP/1.0 协议

参考:RFC 2324 / RFC 7168

直接在手机上用 nc 发请求

Flag:flag{delivering_tea_to_DaLa0}

家里有矿 (750pt)

sha1 (Solved, 150pt)

Google 有个现成的 sha1 碰撞,是两个 pdf 文件。

pdf 文件下载:https://shattered.io/

直接将两个 pdf 文件作为 nonce1 和 nonce2 提交,就能得到 Flag。

import requests
import json
import hashlib
from base64 import *

url='http://202.38.95.46:12006'

s=requests.session()
r=s.post(url+'/getjob')
r=json.loads(r.text)
suffix=bytes(r['suffix'])

pdf1=requests.get('https://shattered.io/static/shattered-1.pdf').content
pdf2=requests.get('https://shattered.io/static/shattered-2.pdf').content

data={'nonce1':b64encode(pdf1),'nonce2':b64encode(pdf2),'coin':1}
r=s.post(url+'/submitjob',data)
print r.text

Flag:flag{sha1_21d0e7b1be5a3cae}

md5 (Solved, 150pt)

写个脚本跑,加上约束条件。开了 8 个 python 程序,跑了半个小时就出结果了。

import requests
import json
import time
import hashlib
from base64 import *
import random
import string

def NumberOf0(n,length1,length2,length3):
    return bin(n)[2:].rjust(length1,'0')[length2:length3].count('0')

url='http://202.38.95.46:12006'

rand_list=''
for i in range(256):
    rand_list+=chr(i)

match_nonce1=''
match_nonce2=''
while True:
    nonce_table=[]
    hash_table=[]
    t=time.time()
    s=requests.session()
    r=s.post(url+'/getjob')
    r=json.loads(r.text)
    suffix=r['suffix']
    print 'suffix: %s' % suffix
    nonce1=''.join(random.sample(rand_list,8))
    hash1=hashlib.md5(nonce1+bytes(suffix[:16])).hexdigest()
    hash1=int(hash1,16)
    nonce_table.append(nonce1)
    hash_table.append(hash1)
    match=0
    while match<102 and t+60>time.time():
        #print 'len: %d' % len(hash_table)
        match=0
        while True:
            nonce2=''.join(random.sample(rand_list,8))
            hash2=hashlib.md5(nonce2+bytes(suffix[:16])).hexdigest()
            hash2=int(hash2,16)
            if NumberOf0(hash1^hash2,128,0,20)<17: continue
            break
        for i in range(len(hash_table)):
            match=NumberOf0(hash_table[i]^hash2,128,0,128)
            if match>95: print match
            if match<102: continue
            match_nonce1=nonce_table[i]
            match_nonce2=nonce2
            break
        nonce_table.append(nonce2)
        hash_table.append(hash2)
    if match<102: continue
    data={'nonce1':b64encode(match_nonce1),'nonce2':b64encode(match_nonce2),'coin':0}
    r=s.post(url+'/submitjob',data)
    print r.text
    break

Flag:flag{md5_7cfa0da2c09776ae}

sha256 (Unsolved, 350pt)

未解出

秘籍残篇 (550pt)

滑稽 Art (Unsolved, 150pt)

未解出

天书易解 (Unsolved, 400pt)

未解出

猫咪遥控器 (Solved, 200pt)

根据提示,猜测需要把给出的控制方向画出轨迹,直接在手机上画吧。

seq=[]

r=open('seq.txt').read()

now=[130,1]
for i in r:
    if 'L'==i:
        seq.append(now)
        now=[now[0],now[1]-1]
    if 'R'==i:
        seq.append(now)
        now=[now[0],now[1]+1]
    if 'D'==i:
        seq.append(now)
        now=[now[0]-1,now[1]]
    if 'U'==i:
        seq.append(now)
        now=[now[0]+1,now[1]]

op=''
for y in range(550):
    for x in range(130):
        if [x,y] in seq:
            op+='A'
        else:
            op+=' '
    op+='n'
print op

Flag:flag{MeowMeow}

她的诗 (Solved, 200pt)

这首诗经过 uuencode 编码,有点像 base64 的编码方式,可以在最后隐写字符。

from codecs import decode

lines = open("poem.txt", "r").readlines()

flag=''
for i in lines:
    i=i[:-1]
    j=1
    s=''
    while True:
        a=i[j:j+4]
        if len(a)<=0: break
        a=a.ljust(4,' ')
        b=chr((((ord(a[0])-32)<<2)&0xff)+((ord(a[1])-32)>>4))
        c=chr((((ord(a[1])-32)<<4)&0xff)+((ord(a[2])-32)>>2))
        d=chr((((ord(a[2])-32)<<6)&0xff)+(ord(a[3])-32))
        s+=b+c+d
        j+=4
    data = "begin 666 <data>n" + i + " nendn"
    decode_data = decode(data.encode("ascii"), "uu").decode("ascii")
    flag+=s[len(decode_data):]
print flag

Flag:flag{STegAn0grAPhy_w1tH_uUeNc0DE_I5_50_fun}

猫咪克星 (Solved, 200pt)

给出 python3 表达式,只需要算出结果提交。然后不断循环 n 次,就能得到 Flag。

PS:话说,我用 python2 也可以解。

from pwn import *

context.log_level='debug'
io=remote('202.38.95.46', 12009)

io.recvline()

for i in range(200):
    res=io.recvline()
    if 'flag' in res:
        print res
        break
    res=res.replace(b"__import__('time').sleep",b'')
    res=res.replace(b'exit()',b'0')
    res=res.replace(b'\x',b'')
    res=res.replace(b'print',b'len')
    res=str(eval(res))
    io.sendline(res)

Flag:flag{'Life_1s_sh0rt_use_PYTH0N'*1000}

猫咪电路 (Solved, 200pt)

出门在外地,凌晨去网咖通宵做题,顺便把这题 mc 给秒了。

作为 mc 老玩家,觉得很简单啊,而且这个红石电路不算复杂。

Flag:flag{0110101000111100101111111111111111111010}

FLXG 的秘密 (550pt)

来自未来的漂流瓶 (Unsolved, 200pt)

未解出

难以参悟的秘密 (Unsolved, 350pt)

未解出

C 语言作业 (Solved, 250pt)

简单 pwn。程序看上去好像没什么问题。

后来发现触发 signal 可以任意命令执行。

那么可以输入 2147483648/-1 来触发 SIGFPE 信号。

带有 sh 的命令被黑名单,那么我们使用 vim 的命令执行功能来执行任意命令

然后执行 :!/bin/sh 打开 shell

发现 flag 文件被改名为 -

不过我们可以执行 vim -- - 打开它,然后就看到 Flag 了

Flag:flag{816484e67b21efd5de8f1661d180a007}

加密算法和解密算法 (Solved, 250pt)

由于是 BrainFuck 虚拟机指令,我直接上网找 BrainFuck To C 的转换。

得到 C 代码,分析,每 10 字节一分组进行加密。改动明文中的一位,都会影响加密结果的每一位。

加密过程可以整理出 10 条方程式,直接上 z3 求解。

from z3 import *

flag=''
table='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'

x=[BitVec('x%d' % i,8) for i in range(10)]
solver = Solver()
solver.add((x[0]*23+x[1]*5+x[2]*40+x[3]*61+x[4]*47+x[5]*21+x[6]*62+x[7]*9+x[8]*18+x[9]*17+2)%64==9)
solver.add((x[0]*46+x[1]*3+x[2]*40+x[3]*54+x[4]*31+x[5]*23+x[6]*54+x[7]*11+x[9]*5+6)%64==51)
solver.add((x[0]*21+x[1]*16+x[2]*63+x[3]*33+x[4]*60+x[5]*26+x[6]*39+x[7]*32+x[8]*48+x[9]*39+8)%64==17)
solver.add((x[0]*16+x[1]*27+x[2]*5+x[3]*53+x[4]*37+x[5]*17+x[6]*24+x[7]*61+x[8]*23+x[9]*50+8)%64==21)
solver.add((x[0]*35+x[1]*22+x[2]*2+x[3]*43+x[4]*4+x[5]*36+x[6]*3+x[7]*22+x[8]*58+x[9]*37+3)%64==15)
solver.add((x[0]*17+x[2]*51+x[3]*46+x[4]*37+x[5]*44+x[6]*11+x[7]*13+x[8]*7+x[9]*18+5)%64==34)
solver.add((x[0]*34+x[1]*15+x[2]*10+x[3]*52+x[4]*27+x[5]*19+x[6]*38+x[7]*15+x[8]*30+x[9]*4+5)%64==21)
solver.add((x[0]*19+x[1]*38+x[2]*52+x[3]*8+x[4]*49+x[5]*7+x[6]*36+x[7]*40+x[8]*60+x[9]*45+7)%64==41)
solver.add((x[0]*12+x[1]*55+x[2]*41+x[3]*4+x[4]*39+x[5]*62+x[6]*48+x[7]*1+x[8]*21+x[9]*2+4)%64==42)
solver.add((x[0]*38+x[1]*14+x[2]*43+x[3]*59+x[4]*55+x[5]*10+x[6]*50+x[7]*18+x[8]*36+x[9]*13+9)%64==40)
for i in range(10): solver.add(x[i] >= 0)
for i in range(10): solver.add(x[i] <= 63)
res=[]
while solver.check() == sat:
    res=solver.model()
    break

tmp_flag=''
for i in range(len(x)):
    tmp_flag+=table[res[x[i]].as_long()]
flag+=tmp_flag

x=[BitVec('x%d' % i,8) for i in range(10)]
solver = Solver()
solver.add((x[0]*23+x[1]*5+x[2]*40+x[3]*61+x[4]*47+x[5]*21+x[6]*62+x[7]*9+x[8]*18+x[9]*17+2)%64==56)
solver.add((x[0]*46+x[1]*3+x[2]*40+x[3]*54+x[4]*31+x[5]*23+x[6]*54+x[7]*11+x[9]*5+6)%64==34)
solver.add((x[0]*21+x[1]*16+x[2]*63+x[3]*33+x[4]*60+x[5]*26+x[6]*39+x[7]*32+x[8]*48+x[9]*39+8)%64==3)
solver.add((x[0]*16+x[1]*27+x[2]*5+x[3]*53+x[4]*37+x[5]*17+x[6]*24+x[7]*61+x[8]*23+x[9]*50+8)%64==12)
solver.add((x[0]*35+x[1]*22+x[2]*2+x[3]*43+x[4]*4+x[5]*36+x[6]*3+x[7]*22+x[8]*58+x[9]*37+3)%64==60)
solver.add((x[0]*17+x[2]*51+x[3]*46+x[4]*37+x[5]*44+x[6]*11+x[7]*13+x[8]*7+x[9]*18+5)%64==28)
solver.add((x[0]*34+x[1]*15+x[2]*10+x[3]*52+x[4]*27+x[5]*19+x[6]*38+x[7]*15+x[8]*30+x[9]*4+5)%64==30)
solver.add((x[0]*19+x[1]*38+x[2]*52+x[3]*8+x[4]*49+x[5]*7+x[6]*36+x[7]*40+x[8]*60+x[9]*45+7)%64==37)
solver.add((x[0]*12+x[1]*55+x[2]*41+x[3]*4+x[4]*39+x[5]*62+x[6]*48+x[7]*1+x[8]*21+x[9]*2+4)%64==50)
solver.add((x[0]*38+x[1]*14+x[2]*43+x[3]*59+x[4]*55+x[5]*10+x[6]*50+x[7]*18+x[8]*36+x[9]*13+9)%64==46)
for i in range(10): solver.add(x[i] >= 0)
for i in range(10): solver.add(x[i] <= 63)
res=[]
while solver.check() == sat:
    res=solver.model()
    break

tmp_flag=''
for i in range(len(x)):
    tmp_flag+=table[res[x[i]].as_long()]
flag+=tmp_flag

x=[BitVec('x%d' % i,8) for i in range(10)]
solver = Solver()
solver.add((x[0]*23+x[1]*5+x[2]*40+x[3]*61+x[4]*47+x[5]*21+x[6]*62+x[7]*9+x[8]*18+x[9]*17+2)%64==56)
solver.add((x[0]*46+x[1]*3+x[2]*40+x[3]*54+x[4]*31+x[5]*23+x[6]*54+x[7]*11+x[9]*5+6)%64==34)
solver.add((x[0]*21+x[1]*16+x[2]*63+x[3]*33+x[4]*60+x[5]*26+x[6]*39+x[7]*32+x[8]*48+x[9]*39+8)%64==3)
solver.add((x[0]*16+x[1]*27+x[2]*5+x[3]*53+x[4]*37+x[5]*17+x[6]*24+x[7]*61+x[8]*23+x[9]*50+8)%64==12)
solver.add((x[0]*35+x[1]*22+x[2]*2+x[3]*43+x[4]*4+x[5]*36+x[6]*3+x[7]*22+x[8]*58+x[9]*37+3)%64==60)
solver.add((x[0]*17+x[2]*51+x[3]*46+x[4]*37+x[5]*44+x[6]*11+x[7]*13+x[8]*7+x[9]*18+5)%64==28)
solver.add((x[0]*34+x[1]*15+x[2]*10+x[3]*52+x[4]*27+x[5]*19+x[6]*38+x[7]*15+x[8]*30+x[9]*4+5)%64==30)
solver.add((x[0]*19+x[1]*38+x[2]*52+x[3]*8+x[4]*49+x[5]*7+x[6]*36+x[7]*40+x[8]*60+x[9]*45+7)%64==37)
solver.add((x[0]*12+x[1]*55+x[2]*41+x[3]*4+x[4]*39+x[5]*62+x[6]*48+x[7]*1+x[8]*21+x[9]*2+4)%64==50)
solver.add((x[0]*38+x[1]*14+x[2]*43+x[3]*59+x[4]*55+x[5]*10+x[6]*50+x[7]*18+x[8]*36+x[9]*13+9)%64==46)
for i in range(10): solver.add(x[i] >= 0)
for i in range(10): solver.add(x[i] <= 63)
res=[]
while solver.check() == sat:
    res=solver.model()
    break

tmp_flag=''
for i in range(len(x)):
    tmp_flag+=table[res[x[i]].as_long()]
flag+=tmp_flag

x=[BitVec('x%d' % i,8) for i in range(10)]
solver = Solver()
solver.add((x[0]*23+x[1]*5+x[2]*40+x[3]*61+x[4]*47+x[5]*21+x[6]*62+x[7]*9+x[8]*18+x[9]*17+2)%64==6)
solver.add((x[0]*46+x[1]*3+x[2]*40+x[3]*54+x[4]*31+x[5]*23+x[6]*54+x[7]*11+x[9]*5+6)%64==55)
solver.add((x[0]*21+x[1]*16+x[2]*63+x[3]*33+x[4]*60+x[5]*26+x[6]*39+x[7]*32+x[8]*48+x[9]*39+8)%64==4)
solver.add((x[0]*16+x[1]*27+x[2]*5+x[3]*53+x[4]*37+x[5]*17+x[6]*24+x[7]*61+x[8]*23+x[9]*50+8)%64==12)
solver.add((x[0]*35+x[1]*22+x[2]*2+x[3]*43+x[4]*4+x[5]*36+x[6]*3+x[7]*22+x[8]*58+x[9]*37+3)%64==10)
solver.add((x[0]*17+x[2]*51+x[3]*46+x[4]*37+x[5]*44+x[6]*11+x[7]*13+x[8]*7+x[9]*18+5)%64==34)
solver.add((x[0]*34+x[1]*15+x[2]*10+x[3]*52+x[4]*27+x[5]*19+x[6]*38+x[7]*15+x[8]*30+x[9]*4+5)%64==33)
solver.add((x[0]*19+x[1]*38+x[2]*52+x[3]*8+x[4]*49+x[5]*7+x[6]*36+x[7]*40+x[8]*60+x[9]*45+7)%64==51)
solver.add((x[0]*12+x[1]*55+x[2]*41+x[3]*4+x[4]*39+x[5]*62+x[6]*48+x[7]*1+x[8]*21+x[9]*2+4)%64==46)
solver.add((x[0]*38+x[1]*14+x[2]*43+x[3]*59+x[4]*55+x[5]*10+x[6]*50+x[7]*18+x[8]*36+x[9]*13+9)%64==7)
for i in range(10): solver.add(x[i] >= 0)
for i in range(10): solver.add(x[i] <= 63)
res=[]
while solver.check() == sat:
    res=solver.model()
    break

tmp_flag=''
for i in range(len(x)):
    tmp_flag+=table[res[x[i]].as_long()]
flag+=tmp_flag

print 'Flag: flag{%s}' % flag

Flag:flag{h1ll-c1ph3r-w1th-10xr-w1th-10xbl3-matr1x}

王的特权 (Unsolved, 250pt)

未解出

她的礼物 (Solved, 250pt)

把文件里 call sleep system signal alarm 的地方用 0x90 NOP 填充

把除了 输出 Key 之外无关 putsprintf 也用 0x90 NOP 填充

然后运行程序,把“她的诗”解密后第 10 行提交过去:

However, someday, someone will find it.

不用半分钟就能自动输出 Flag

Flag:flag{HowEVER,_Somedaj,_sOMe0NE_wILl_FiND_it.}

困惑的 flxg 小程序 (Unsolved, 250pt)

未解出

CWK的试炼 (650pt)

神庙设计图, Get! (Solved, 250pt)

用 Google 的 dwebp.exe 工具将 webp 图片转为 png 图片。

Stegsolve 打开 png 图片,Green 第 0 通道 隐写了一个 onion 地址,然后就想到 tor

Onion 地址:ustcctfbase7l74q.onion 2333

tor 代理 nc 连接这个 onion 地址,提示需要输入 blueprintCRC32 才能继续。

然后还提示 blueprint 用类似的方法藏在图片内。

其实 blueprint 是一个 ELF 文件,经过 base64 编码后,逐 bit 以黑白代表 01 藏在了 Green 第 0 通道 中神庙的区域内。

经过处理,得到 webp.bmp 文件:

然后写个脚本把 blueprint 提取出来并算 CBC32 值。

from PIL import Image
from base64 import *
import binascii

im=Image.open('webp.bmp')
w=im.size[0]
h=im.size[1]

def bw(color):
    if color==(0,0,0):
        return 0
    else:
        return 1

coffset=[]
for i in range(615):
    coffset.append([0,0,0])

i=0
for y in range(h):
    for x in range(w):
        if bw(im.getpixel((x,y)))==1:
            coffset[i][0]=y
            coffset[i][1]=x
            i+=1
            break

i=0
for y in range(h):
    for x in range(w):
        if bw(im.getpixel((w-x-1,y)))==1:
            coffset[i][2]=w-x-1
            i+=1
            break

#print coffset

table='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
raw=''

i=0
for offset in coffset:
    tmp_raw=''
    data=''
    y=offset[0]
    for x in range(offset[1],offset[2]+1):
        data+=str(bw(im.getpixel((x,y))))
    #print data
    if i==0:
        raw+='0'+data
    else:
        match_1=0
        for j in range(0,8):
            tmp_raw=raw[len(raw)/8*8:]
            tmp_raw+='0'*j+data
            match_2=1
            for k in range(len(tmp_raw)/8):
                if chr(int(tmp_raw[k*8:k*8+8],2)) not in table:
                    match_2=0
                    break
            if match_2==1:
                match_1=1
                raw+='0'*j+data
                break
        if match_1==0:
            print 'error'
    i+=1

s=''
for t in range(len(raw)/8):
    s+=chr(int(raw[t*8:t*8+8],2))
length=len(s)/4*4
if length!=len(s): length+=4
s=s.ljust(length,'=')
s=b64decode(s)

open('trial.elf','wb').write(s)
print 'CRC32: %X' % (binascii.crc32(s) & 0xffffffff)

CRC32:3D6540C7

将 CRC32 提交过去,拿到 Flag

Flag:flxg{But_the_Sun_Also_Rises}

此小技耳 (Unsolved, 400pt)

未解出

Z 同学的 RSA (Unsolved, 300pt)

未解出

数理基础扎实的发烧友 (Unsolved, 300pt)

未解出

一些宇宙真理 (Unsolved, 300pt)

未解出

对抗深渊 (Unsolved, 350pt)

未解出

Source: impakho.com | Author:impakho

相关推荐: PDF生成漏洞:从XSS到服务端任意文件读取

一、 前言 XSS是最为常见的Web漏洞之一,多年来连续入选OWASP TOP 10,相信大家都耳熟能详。 它是一种代码注入类的攻击,是一种客户端侧的攻击,攻击者通过在Web应用中注入恶意JavaScript代码,通过点击URL,最终在受害者浏览器端执行的一种漏洞。主要有反射型XSS、存储型XSS、基于DOM的XSS三类。 XSS一些比较常规的危害大概有:重定向浏览器、窃取Cookie、浏览器劫持等。 与常规的XSS介绍不同,本篇文章侧重于发现XSS后的进一步利用。 主要介绍在某次实际测试过程中,发现XSS漏洞之后,如何进一步的利用,最终通过XSS达到服务端任意文件读取的危害。 二、 漏洞详情 在某个Web站点中,发现了一处可以让我们下载PDF的功能,大概的URL如下: https://xxx.com/pay/downloadStatements?Id=xxxx&utrnumber=testxyz&date=2020-08-17 测试过程中发现,URL中的utrnumber字段的值在PDF文件中被渲染,所以尝试用类似**"><s>aaa这样的html代码来当做该字段的值,也就是如下的URL https://xxx.com/pay/downloadStatements?Id=xxxx&utrnumber="><s>aaa&date=2020-08-17 访问该URL,打开获取到的PDF文件,发现"><s>aaa被当做HTML渲染,这就导致了XSS。结果如下: 尝试过用< iframe>标签来探测内网和file协议来读取文件,但都失败了。 在此之后,尝试使用JavaScript来进行进一步的探索,但是目前不不确定PDF的渲染过程中,是否执行了JavaScript脚本。所以尝试使用如下脚本来观察JS是否成功执行。 <p id="test">123</p>  < script>      document.getElementById('test').innerHTML='aaaa'  </script>    <!-- or this -->  <img src=x onerror=document.write("aaaa")> 对应URL为: https://xxx.com/pay/downloadStatements?Id=xxxx&utrnumber=<img src=x onerror=document.write("aaaa")>&date=2020-08-17 观察到JavaScript脚本成功执行。 接下来,检查了一下JavaScript执行所在context,令人惊喜的是这段脚本,在服务端是在file://下执行的,这也就意味着我们或许可以借此来达到任意文件读取的效果。 https://xxx.com/pay/downloadStatements?Id=xxxx&utrnumber=<img src=x onerror=document.write(<img src=x onerror=document.write('aaaa'%2bwindow.location)>)>&date=2020-08-17 接下来,尝试通过 XHR(XMLHttpRequest)来读取服务器端文件的内容,简单的PoC如下: < script>      x=new XMLHttpRequest;      x.onload=function(){        document.write(this.responseText)  };      x.open("GET","file:///etc/passwd");      x.send();  </script> 也即访问如下URL,下载对应的PDF文件: https://xxx.com/pay/downloadStatements?Id=xxxx&utrnumber=< script>x=new XMLHttpRequest;x.onload=function(){document.write(this.responseText)};x.open("GET","file:///etc/passwd");x.send();</script>&date=2020-08-17 接下来查看对应 的PDF文件内容,发现成功读取到了passwd文件的内容 至此,我们就完成了服务端XSS到服务端的任意文件读取,然后就能读取服务器上随便一个文件的内容啦。 三、 总结 XSS是Web中很常见的一种漏洞,我们在日常的漏洞挖掘中,如果发现了XSS,不妨结合具体的应用功能做进一步的挖掘,尝试扩大XSS的危害,本次挖掘就利用XSS达到了的服务端任意文件读取的效果。 参考/学习资料: https://www.aptive.co.uk/blog/xss-cross-site-scripting/ https://www.bugcrowd.com/resources/webinars/cross-site-scripting/ 相关推荐: JavaWeb中的权限控制——Spring AOP一、前言   在实际开发场景中经常需要解决接口权限鉴别问题,能处理的方式有很多种,例如可以直接在controller中和service调用中识别用户身份,或者根据数据库返回的entity判断对应的creator是否为当前user,也可以使用…

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
[db:作者]
  • 本文由 发表于 2021年11月29日17:54:14
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   中国科学技术大学第五届信息安全大赛 —— USTC Hackergame 2018 WriteUphttp://cn-sec.com/archives/653430.html

发表评论

匿名网友 填写信息