xctf中php_rec的writeup,一个GET请求拿到flag——XCTF 2018 Final PUBG(WEB 2) Writeup

环境

XCTF Final 和 HITB 赶在了周四周五,周四晚上拿到题目,此时队友已经对PHP代码完成了解密工作。

解密后的代码: http://static.cdxy.me/DECODED.zip

github:https://github.com/Xyntax/XCTF-2018-Final-WEB2-PUBG

解密后的代码读起来有点麻烦,并无大碍。

1586fc0b8d8c28078d50a2f0b909757d.png

有点魔幻的get flag过程

当晚并没有找到突破口,但发现kss_admin/admin_update函数疑似是exp链路中的一环。

其中120行发现CMS更新功能,从远端主站拉取代码写入本地:

$_obfuscate_koiKkIiPjI6UkYeRlIqNhoc� = _obfuscate_lY6Gk5KMkYmPjIyPhpCOlYc�( "http://api.hphu.com/import/".$_obfuscate_koaSiYqGjIqMiZSLk4uGiZU�.".php?phpver=".PHP_VERSION."&webid=".WEBID."&rid=".time( ), 300 );

跟进Yc函数,发现其注册了两个curl的回调 read_header,read_body:

curl_setopt( $_obfuscate_joiNh4aIhouViZGQho_JiI4�, CURLOPT_HEADERFUNCTION, "read_header" );

curl_setopt( $_obfuscate_joiNh4aIhouViZGQho_JiI4�, CURLOPT_WRITEFUNCTION, "read_body" );

其中read_body函数会将curl到的content写到本地文件kss_tool/_webup.php

file_put_contents( KSSROOTDIR."kss_tool".DIRECTORY_SEPARATOR."_webup.php", $_obfuscate_jJWMiJWJjoyIkYmLjY6VipM�, FILE_APPEND );

想要使用admin_upload.php这个点写shell,需要满足两个条件:

绕过admin权限验证

能控制curl部分的回显

周四当晚并没有突破。周五早9点比赛环境恢复,我打开ipython对这个疑似webshell的地址kss_tool/_webup.php做了监控。如果这个文件被其他队动了,就证明这个思路是可行的。

In [1]: while True:

...: try:

...: r = requests.get('http://guaika.txmeili.com:8888/kss_tool/_webup.php')

...: except Exception,e:

...: print e

...: continue

...: if r.content not in ans:

...: print r.content

...: ans.append(r.content)

结果发现这个文件的http response在一直变化,看着看着flag就出来了....

8fd8620ac5bc46d34847706ba9a49917.png

然后提交拿了2血,几秒之后看到De1ta也交了flag,感谢De1ta的WEB大佬们送的火箭!

解题过程

当天下午完整打通了exp过程,分为三个部分:

找到注入点,偷数据

构造cookie,拿到admin权限

通过更新功能写shell到本地,读flag

SQL注入

CMS对SQL注入的防御策略

kss_inc/function github link

实现了多种过滤方案,然后在SQL语句拼接取参时,通过传入参数指定取参的位置(GET/POST/COOKIE)和过滤方案(sql/sqljs/num等)

外部取参的代码示例:

$_obfuscate_iJWMjIiVi5OGjJOViY2Li48� = _obfuscate_i4mIkpOGkomKiouRhoaMh5I�( "out_trade_no", "pg", "sql", "" );

意思是从POST/GET(pg)中取出参数out_trade_no的值,然后通过sql过滤器的检查后,赋值到i48变量。

先简单看下过滤器的正则:

case "sql" :

if ( preg_match( "/select|insert|update|delete |union|into|load_file|outfile|char|0x[0-9a-f]{6}|\\.\\/|\\/\\*|'/i", $_obfuscate_ipCJlJOSlJSQkYqNlYqKlIs˙ ) )

{

ob_clean( );

$_obfuscate_ipCJlJOSlJSQkYqNlYqKlIs˙ = preg_replace( "/(select|insert|update|delete |union|into|load_file|outfile|char|0x[0-9a-f]{6}|\\.\\/|\\*|')/i", "$1", $_obfuscate_ipCJlJOSlJSQkYqNlYqKlIs˙ );

exit( "

MySQL injection:".$_obfuscate_lIyOioeNkY6Vj4qPkJGMiJQ˙.",".$_obfuscate_iYyTho_HlJCOh4yRj4ePj4k˙.",".$_obfuscate_ipCJlJOSlJSQkYqNlYqKlIs˙."

" );

过滤了',然后匹配到这些危险字符时,会将参数带到html回显,使response可控(XSS敏感)。

正则写的没啥问题,接下来两个方向:

找到忘记使用过滤器直接传参的场景

找到外部没用'包裹的拼接,构造注入

注入构造

kss_inc/payapi_return2.php是一个外部支付功能。其中的chinabank,e138两种支付方式均存在"未使用过滤器"直接传参的漏洞。

else if ( $_obfuscate_kYyPkY_PkJKVh4qGjJGIio4� == "chinabank" )

{

$_obfuscate_kpGPh4mNh46SkZONh4eLlJU� = "";

$_obfuscate_k42NkY2RkoiNjJCKlZSKiIg� = trim( $_POST['v_oid'] );

$_obfuscate_iJWMjIiVi5OGjJOViY2Li48� = $_obfuscate_k42NkY2RkoiNjJCKlZSKiIg�;

$_obfuscate_iIuQkYaUioqGlI6IjIuMiI8� = trim( $_POST['v_pstatus'] );

$_obfuscate_jpGJk5SSkJOIk4iQiI_OhpU� = trim( $_POST['v_amount'] );

$_obfuscate_lIuQk5OGjpKVjY6UiI_QjJM� = $_obfuscate_jpGJk5SSkJOIk4iQiI_OhpU�;

$_obfuscate_hpCRlJCSjI6Ki5WSipCLkpQ� = trim( $_POST['v_moneytype'] );

$_obfuscate_lJSPjJCOi5CIiJSSkZWNh4Y� = trim( $_POST['remark1'] );

$_obfuscate_iImJjYmQjYyOjIuVkIuMjIs� = trim( $_POST['v_md5str'] );

if ( $_obfuscate_iIuQkYaUioqGlI6IjIuMiI8� == "20" )

{

$_obfuscate_i5CMioaGiI6ShomNiIuKjJE� = "TRADE_FINISHED";

}

else

{

$_obfuscate_i5CMioaGiI6ShomNiIuKjJE� = "WAIT_BUYER_PAY";

}

}

else if ( $_obfuscate_kYyPkY_PkJKVh4qGjJGIio4� == "e138" )

{

$_obfuscate_kpGPh4mNh46SkZONh4eLlJU� = "";

$_obfuscate_k42NkY2RkoiNjJCKlZSKiIg� = trim( $_POST['SerialNo'] );

$_obfuscate_iJWMjIiVi5OGjJOViY2Li48� = $_obfuscate_k42NkY2RkoiNjJCKlZSKiIg�;

$_obfuscate_iIuQkYaUioqGlI6IjIuMiI8� = trim( $_POST['Status'] );

$_obfuscate_jpGJk5SSkJOIk4iQiI_OhpU� = trim( $_POST['Money'] );

$_obfuscate_lIuQk5OGjpKVjY6UiI_QjJM� = $_obfuscate_jpGJk5SSkJOIk4iQiI_OhpU�;

$_obfuscate_iImJjYmQjYyOjIuVkIuMjIs� = trim( $_POST['VerifyString'] );

if ( $_obfuscate_iIuQkYaUioqGlI6IjIuMiI8� == "2" )

{

$_obfuscate_i5CMioaGiI6ShomNiIuKjJE� = "TRADE_FINISHED";

}

else

{

$_obfuscate_i5CMioaGiI6ShomNiIuKjJE� = "WAIT_BUYER_PAY";

}

}

SQL执行时GP被带入i48变量。

$_obfuscate_lZGQj4iOj4mTlZGNjZGUj5E� = $_obfuscate_jIaUiIeSjZWKlIqLkIqOioc�->_obfuscate_iY6OkJCRkY2PjpCPk5CRkJA�( "select * from kss_tb_order where ordernum='".$_obfuscate_iJWMjIiVi5OGjJOViY2Li48�."'" );

这里因为没有过滤,可以'闭合然后构造一个布尔盲注。

5b498b6722c9a95c2006467c7aa16ab0.png

1875dce9bbef9c5d068738ba129a9c60.png

Cookie构造

在使用admin_upload.php写shell之前,有权限校验,可使用从数据库中注出的数据,按源码的验证逻辑构造出cookie,拿到admin权限。

cookie构造逻辑在kss_inc/db_function.php line 300。

有两个k-v需要构造,下图红框部分为注入跑出来的数据,蓝框部分从源码配置文件里拿到:

a4da19d9d3ce21539b7def397bb20b32.png

webshell写入

回到最开始提到的从远程服务器更新代码的逻辑:

$_obfuscate_koiKkIiPjI6UkYeRlIqNhoc� = _obfuscate_lY6Gk5KMkYmPjIyPhpCOlYc�( "http://api.hphu.com/import/".$_obfuscate_koaSiYqGjIqMiZSLk4uGiZU�.".php?phpver=".PHP_VERSION."&webid=".WEBID."&rid=".time( ), 300 );

URL里面拼接的变量是外部可控的,我们在这个主站的test目录下发现了一套Demo的CMS:

http://api.hphu.com/test/kss_admin/index.php

回想之前的SQL注入过滤机制,我们可以触发这个机制,将php代码写入http回显,然后admin_upload.php通过curl读内容时会将页面中的php代码写入_webup.php,完成webshell植入。

主站回显构造:

18f87adbb29b8324c369768845355f0a.png

Exp构造(带上之前构造好的cookie):

f33abd96419bf23343f62df2ee946204.png

最终将可控回显写入_webup.php

36be42498458458317fe8de752a6cb67.png

然后通过webshell读到C盘根目录下的flag文件。

给 @r3kapig 队友递茶

给提供思路的队内WEB大佬递茶 @麦香 @zzm @hear7v @lynahex @n0b0dy

给本题做的比我们快的 @Dubhe 和 @De1ta 两队WEB大佬递茶

给出题人递茶 @RicterZ

def0d36302c4e79487a68002884fdf43.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值