欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

URL编码的一些思考

程序员文章站 2022-07-12 14:58:00
...

关于URL编码和简单的绕过的思考

本文仅作为我自己的学习过程的记录

前言:一直以来,我对于URL编码一直都不太感冒,虽然大概了解是怎么编码的,但总还是差点感觉(可能是刚刚入门,太菜),直到我遇到一个简单的绕过题,很适合去了解URL编码的一些知识.

例题

题目链接

打开页面发现如图:
URL编码的一些思考
尝试输入数据,无果,只好先查看源码,发现可疑的链接如图

<body> 
<div class="loginform cf"> 
    <form name="login" action="index.php" method="POST" accept-charset="utf-8"> 
        <ul> 
            <li> 
                <label for="SMILE">请使用微笑过关<a href="?view-source">源代码</a></label>//可疑的链接 
                <input type="text" name="T_T" placeholder="where is your smile" required> 
            </li> 
            <li><input type="submit" value="Show"> </li> 
        </ul> 
    </form> 
</div> 
</body> 

尝试和主URL拼接,成功得到一段PHP源码又是PHP代码审计题

<?php  
    header("Content-type: text/html; charset=utf-8");
    if (isset($_GET['view-source'])) { 
        show_source(__FILE__); 
        exit(); 
    } 

    include('flag.php'); 

    $smile = 1;  

   	if (!isset ($_GET['^_^'])) $smile = 0;  //判断^_^参数是否存在
    if (preg_match ('/\./', $_GET['^_^'])) $smile = 0;  //^_^参数的值中没有'.'
    if (preg_match ('/%/', $_GET['^_^'])) $smile = 0;   //^_^参数的值中没有'%'
    if (preg_match ('/[0-9]/', $_GET['^_^'])) $smile = 0;   //^_^参数的值中没有数字
    if (preg_match ('/http/', $_GET['^_^']) ) $smile = 0;  //^_^参数的值中没有字符串'http'
    if (preg_match ('/https/', $_GET['^_^']) ) $smile = 0;  //^_^参数的值中没有字符串'https'
    if (preg_match ('/ftp/', $_GET['^_^'])) $smile = 0;  //^_^参数的值中没有字符串'ftp'
    if (preg_match ('/telnet/', $_GET['^_^'])) $smile = 0;  //^_^参数的值中没有字符串'telent'
    if (preg_match ('/_/', $_SERVER['QUERY_STRING'])) $smile = 0; //查询字符串中没有字符'_'
    if ($smile) { 
        if (@file_exists ($_GET['^_^'])) $smile = 0;  //以^_^参数的值为文件名的文件不存在
    }  
    if ($smile) { 
        $smile = @file_get_contents ($_GET['^_^']);  //将^_^参数的值以字符流读入$smile
        if ($smile === "(●'◡'●)") die($flag);  
    }  
?> 

总的来说:

1.必须对"^_^"赋值
2."^_^"的值不能有  .  %  [0-9]  http  https  ftp  telnet  这些东西
3.$_SERVER['QUERY_STRING'],即"^_^=(输入的值)"这个字符串不能有 _ 这个字符
4.满足$smile!=0
5.file_exists ($_GET['^_^'])必须为0.也就是$_GET['^_^']此文件不存在
6."$smile"必须等于"(●'◡'●)".也就是file_get_contents($_GET['^_^'])必须为"(●'◡'●)",即和5矛盾,文件不存在,又要有数据

其他的都是简单,主要就是3和5,6的绕过
5,6的绕过可以通过data伪协议来从外界读入数据而又不通过文件(data:,(●’◡’●))
这里我们重点关注3的绕过
首先
$_SERVER[‘QUERY_STRING’]

query string(查询字符串),如果有的话,通过它进行页面访问。 简单来说就是用于返回用户实际输入的GET请求的参数以及参数值

<?php
	header("Content-type: text/html; charset=utf-8");
	if (isset($_GET['^_^'])){
		echo 'it is get';
		echo '<br>';
	}
	if(isset($_POST["name"])){
		echo 'it is post';
		echo '<br>';
	}
		echo $_SERVER['QUERY_STRING'];
?>

URL编码的一些思考看了其他大佬的wp有两种解题方法
1.对_进行URL编码绕过
2.利用QUERY_STRING对于特殊字符的解析成"_"绕过

问题就出在第一个绕过上
但当我尝试构造payload=(1)http://lab1.xseclab.com/base13_ead1b12e47ec7cc5390303831b779d47/index.php?^%5f^=data:,(●’◡’●)’’'
发现在浏览器的搜索栏中竟然是:(2)http://lab1.xseclab.com/base13_ead1b12e47ec7cc5390303831b779d47/index.php?_=data:,(●’◡’●)
复制下来之后竟然是这样的:(3)http://lab1.xseclab.com/base13_ead1b12e47ec7cc5390303831b779d47/index.php?^%5f^=data:,(%E2%97%8F%27%E2%97%A1%27%E2%97%8F)
这就让我给搞糊涂了,这什么情况,对于大佬们来说简简单单,对于我来说十分的不解,于是我就去百度,谷歌,查到的信息加上我自己的推测,大致明白了这是怎么回事

URL编码

URL编码遵循下列规则: 每对name/value由&;符分开;每对来自表单的name/value由=符分开。如果用户没有输入值给这个name,那么这个name还是出现,只是无值。任何特殊的字符(就是那些不是简单的七位ASCII,如汉字)将以百分符%用十六进制编码,当然也包括象 =,&;,和 % 这些特殊的字符。其实url编码就是一个字符ascii码的十六进制。不过稍微有些变动,需要在前面加上“%”。比如“\”,它的ascii码是92,92的十六进制是5c,所以“\”的url编码就是%5c。

总结就是:URL编码会对除ASCLL以外的字符进行编码,使其变成%+16进制的模式,同时支持对ASCLL进行编码以满足特殊字符的要求例如"#"

那么为什么会出现(1),(2)两种情况?
原因就是浏览器的地址栏存在自动解码的功能,还是利用上面的代码做个试验

URL:http://localhost/test.%70hp?^%70^=%70

地址栏解析为:http://localhost/test.php?^p^=p
测试发现只要不输入一些特殊的字符的%+16进制,都能够被解析为ASCLL或者是对应的字符
因此地址栏实际上具有服务端一样的解析功能,但是无法对特殊字符或者说是限制对特殊字符的解析功能

那第三种情况是什么呢?再对众多的百度的URL进行测试后发现,这其实是原始的URL,没有经过任何的解析最原始的URL,服务端正是利用这个最原始的URL进行解析得出数据

URL编码绕过

由于URL支持ASCLL和%+16进制的模式,即使是最原始的URL也是由这两部分组成,同时浏览器不会对%+16进制的数据再进行编码,那么如果只是简单直接从url中获取数据,而对输入数据没有转码检查,例如限制"“符号的输入,由于”“可以是ASCLL码直接表示,直接对其匹配而没有对转码后的数据进行检查,那么我们对”“进行URL编码,在url解码后数据还原成”"从而绕过
小结:因此在对用户输入时,最好是对URL解码后的数据进行匹配,或者是双重匹配,避免URL编码绕过.


回到原题
对$SERVER[‘QUERY_STRING’]变量不熟悉的小伙伴,还是可以利用上面的代码进行测试
URL编码的一些思考我们发现不管传入怎么样的格式都会以最原始的URL的数据格式输出,也就是说匹配的是ASCLL形式的"
",那么我们对"“进行编码,就能绕过,同时服务器解析后还原为”",从而不影响其他匹配

关于QUERY STRING解析特殊字符成"_"

这个我也不知道没找到相关的资料(如果有链接的麻烦发我一下,谢谢),只好用BP跑一下了
貌似只有==[.会被解析成"_"==
URL编码的一些思考
参考资料:
[1]:URL特殊字符以及解决办法:https://developer.aliyun.com/article/421813
[2]:ASCLL表:https://www.runoob.com/tags/html-ascii.html


*如若有不足之处,请指出,转载请表明出处

相关标签: URL