陈文青


  • Home

  • Archives

从Python看Ruby

Posted on 2015-05-11

自从大一接触Python,大量使用到现在,已经敢说很熟悉了。

Ruby比起Python,是更脚本的一门语言。有很多人说python不适合大规模的工程,我相信它们不是在拿python跟ruby比。

Ruby糅合了lisp,perl和smalltalk的特点,虽然后两门语言我并没使用过,但参考ruby可看出一点端倪。

至少在一开始,使用Ruby不太可能像python那样为你带来便利。这是由于语法太复杂(体现在语法糖过多);以及库不像python那样丰富。

然而你仍然可以通过使用Ruby获得极大的乐趣,在你看的明白的前提下,它极具美感。

各种最基础的语法

  1. 迭代容器

Python:

for i in list:
  pass

Ruby:

for i in list:
  pass

list.each do |x|
end

仅就这点而言,ruby可以用和python很像的写法,也可以使用后者这种更ruby的形式。

在后面就会看到,ruby中相当多的代码都采取了后面这种形式。

  1. 迭代容器(with index):

    Python:

    for index, i in enumerate(list):
    pass

Ruby:

list.each_with_index do |x, index|
end

enumerate和each_with_index都是自己可以实现的函数。

从个人角度而言,更喜欢后者这种写法,因为它用起自动补全更方便。

  1. 循环10次

    Python:

    for i in range(10):
    pass

Ruby:

10.times do |x|
end

1.upto(10) do |x|
end

在固定循环次数的代码中,ruby比python漂亮地多,而且在代码层面没有引入额外的因素

(一个1..10的list)。

  1. 字符串格式化

    Python:

    “%d %d” % (1,2)
    “{0} is {1}”.format(a, b)

Ruby:

"%d %d" %  [1,2]
"#{a} #{b}"

此处python和ruby都可以采用类似C中sprintf的方式格式化。

同时python提供了类似C#的格式化方式。我很少使用,不是很清楚它比起前一种有何优势。

ruby另外提供的是类似php和perl的语法,使用中感觉更明晰和方便。

  1. 函数返回值

    Python

    def a():
    return x

Ruby:

def a(x)
  x
end

可以看到,Ruby采用了函数式编程语言中常见的,将最后一个求值的表达式作为函数求值结果的形式。

这提供了很大的灵活性,新出现的类C++语言Rust也采取了这种形式。

  1. 正则表达式

    Python:

    import re

    regex = re.compile(r”[Pp]ython”)

    regex.findall(“python2”)

Ruby:

/[Rr]uby/ === "ruby"
/[Rr]uby/ =~ "ruby"

case "ruby"
  when /[Rr]uby/ then 1
  when /ruby/, /Ruby/ then 2
end

a = /ruby/.match("ruby")

继承自perl的风格,ruby的正则表达式是一个内嵌的语法而非通过包导入的字符串处理引擎。

且通过”===”, “=~”等操作符,灵活地完成正则表达式的匹配和处理,比python强出太多。

  1. 字符串匹配

    Python:

    index = “abc”.find(“a”)

    re.findall(r”[Aa]b”, “abc”)

Ruby:

s = "abs"
s["a"]
s[/[aA]b/]

Ruby的风格非常简洁,然而对于第一次接触的人而言有那么点难以理解

  1. Shell命令

    Python:

    import sh
    sh.ls()

    import subprocess
    subprocess.check_output(‘ls -al’.split())

Ruby:

`ls -al`

从这个角度看,ruby能以很类似shell脚本的方式执行命令。

当真的需要定制更复杂的选项时,便可以像python那样以更复杂的方式调用。

Rust ABC

Posted on 2015-04-04

Lisp

Posted on 2015-03-14

打算实现一个lisp解释器,纯做娱乐.

Lisp 七公理

Lisp一开始是作为理论推倒被提出的,只是后来发现它恰好可以真的实现成为编程语言而已. (这看起来就像,python是恰好可以运行的伪代码)
因此它的形式上具备极高的美感(当然,有戏言称lisp程序的最后一页全是右括号,不过要知道那么长的程序,不管什么语言都不会看着很让人愉悦).

在黑客与画家中提到,lisp当年所提出的一些理念,到很多年后才在新生代的编程语言中得到大规模的应用.关于这些理念是什么暂且按下,我们先看一看lisp语言的基础结构.

就像平面几何的五个公理(把平行线公理换掉可以推导出另外的几何体系,这不禁让人想象,如果把lisp的原语换成另外一组会怎么样), lisp有七个公理,是七个基础操作符.

(quote x) => x

quote操作符返回其参数本身,不对其求值,在lisp中通常简写为’x

(atom x) => t | ()

在lisp中,习惯以t表示真,以空表()表示假
atom操作符在x是一个原子或者空表时返回t, 否则返回()

(eq x y) => t | ()

eq操作符即相等操作符,作用不言自明

(car x)

car要求x是一个表,它返回x的第一个元素

(cdr x)

cdr同样要求x是一个表,返回x中除了第一个元素以外的所有元素

(cons x y)

要求y是一个表.返回一个表,其第一个元素是x,后面的元素为y中的所有元素

(cond (p1 e1) (p2 e2) … (pn en))

cond是条件表达式,其复杂程度就像欧几里得的第五个公理.cond将p1到pn依次求值, 直到找到第一个值为t的pi,把对应的ei作为整个表达式的值返回.

七个操作符中,除了quote和cond, 其它操作符会对它的所有参数求值.

lisp 实现

在这里,我要尝试从零开始用python实现一个lisp解释器.

之前说的是那些基本的列表操作,然而通过它们并不足以构建出一个lisp语言,现在引入一些额外的符号.

  1. (define var exp):
    定义var,其值为exp求值的结果

  2. (lambda (p1 p2 … pn) exp):
    表达式的求值结果为一个函数,pi为其参数,exp为其函数体

好吧经过一段时间的学习,我仍是没有完成lisp的实现……不过已经快了。

整个项目放在github上,实现了七个基本原语当中的除cond以外的六个。

前段时间读了读SICP,发觉自己对于lisp的理解还是有很大的偏差,很多我以为是函数的东西,事实上应当被叫做“special form”。这样很多东西就好解释了。

我也曾试图用yacc和lex来处理,后来由于对于lisp理解的偏差没能成功,最后还是用裸写的方式。

有时间再继续吧。

Netforce Writeup

Posted on 2015-02-27

将曾经做过的netforce的题目一并整理到这里来.

顺带一提,wechall的account link功能挺不错的

Training - Nice include system

从标题到url,无不透着一股提示的味道.

瞄一眼url,就能看出这个网页的后台语言是php.include无疑指的就是php的include函数.该函数的作用跟c的include差不多,就是把一个文件包含进当前文件当中.而总有那么些程序员,它们会把include的参数用get的方式提交.这就给了心怀不轨的人一个机会,一个自由访问任何能想的到的文件名的机会.

由于提示已经给的很明显了.我们只要把url中参数的值改成/etc/passwd就可以了.成功~于是就看到了这个文件的内容.很容易找到目标:netforce.我们知道,passwd当中的值都是加过密的,为了解密,只要把得到的hash扔进john the ripper 里就好了.它会自动识别并破解的.于是就得到了想要的结果.

Oops, a typo…

这道题嘛,已经把流程都设计好了,直接跟进就好.

点进第一个链接,发现它写着一堆东西,大概意思是只能用特定ip访问.一开始我的思路被误导到了,要修改自己的ip发http包这个方向上.

然后发现好像没那么复杂,上面那句”undefined”隐约暗示着,这个所谓的ip可能仅仅只是一个php的变量而已.于是,尝试着在url的后面加上ip=213.75.238.147这样的参数提交上去.
果然顺利搞定第一个障碍.

点进第二个链接,发现只显示了个Access Denied

瞄了一眼参数,还是很明显,把denied这参数去掉就好了.

小提醒一下,貌似这个网页有个自动跳转机制,因此建议以curl来访问,能看到跳转的全过程,不会忽略重要的细节.

然后就能看到一个叫做show=no的参数

那么很果断,把show改成yes吧.

终于,看到了最后的密码.

Source Cooking!

该网页提供了一个可以浏览源代码的链接,然而它做了一定限制,只允许访问html文件的源代码.

而我们要寻找的点,无疑是在challenge.php这个文件当中

于是问题的关键就在于,怎么查看challenge.php的源代码,又让php认为它是一个.html文件.

首先不断测试url的值,可以发现source.php的行为大致是,首先判断文件是否存在,再判断后缀名,再读入文件或显示错误.

为了达到上述的欺骗效果,需要了解php的一个bug:nullbyte.

php用c语言实现,因此很多地方,会受到c的字符串风格的影响,将\0视作字符串的结尾.经过测试,不是所有的地方都会有这个问题.echo,字符串比较等都不会有这个问题,然而涉及到用字符串作参数,操作文件的时候,往往会受此影响.

比如判断是否是文件的is_file函数.

于是构造url=challenge.php%00.html 就可以顺利获得challenge.php的内容.

了解到,只要将NetForce的MD5在cookie里提交上去就可以获得密码了.

P.S.在这里出了一些小问题,linux自带的MD5sum和python的hashlib的计算结果不同,结果证明python的计算结果是对的,我一下子也搞不清楚是怎么回事.

Hiding in a pipe…

点进链接之后,可以看到三个输入框.大概尝试了一下,就是分别执行了label标注的那几个命令.看到这种输入,我果断尝试了用分号和&&的方法,尝试注入另外一个命令,然而没有成功.由于题目里已经很明确提到了pipe,用管道再尝试.试了很多个命令都显示command not found.只有ls和cat成功了.

尝试cat /etc/passwd,没权限.尝试ls当前目录,找到了一个加密的需要密码访问的文件夹,和一个表明已经过了第一关的txt.然后再次陷入困顿.

然后好像哪里有点不对劲,我用finger的命令自带的那个user和空密码顺利访问了那个文件夹,然后在里面找到了密码.第一次尝试提交不成功,因为我没把后面的叹号一起复制进去

可问题是,为什么forum里面他们谈论起这道题给我一种很高深莫测的感觉,是题目改了还是我走了什么错误的捷径?

UNION makes FORCE

说起来,这道题其实挺坑的.由于提供了源码,一看就知道这道题肯定是sql注入.当我随手测试了一下这个注入点,却发现无论我怎么修改自己的查询语句,总是显示语法不正确.对照着以前的程序和mysql的书,百思不得其解,什么莫名其妙的状况.

后来在forum里面看了很多,虽然还是没思路,但总算知道了事情的真相是,这后面并没有一个真正的mysql服务器,只有一个模拟的程序,因此对于不是很接近答案的结果,它都会显示错误.

不再去考虑语法错误,可以正式开始思考这个问题了.

我们要做的事情是:使得password的md5hash与查询出来的第一条语句的结果相同.然后,再考虑题目里就有union,采用union查询已经无可非议了.

由于我们不知道数据库里任何一条内容,也不太可能知道,唯一的方法便是我们自己去生成这么一个MD5.与自己输入的password相匹配即可.

我组织了一条这样格式的语句: ‘ union select (….) from users where ‘’=’ , 括号里的内容是一个password的md5hash

还是语法错误,我有点困惑了.很快发现,右下角还有一条注释,要求语句最短.我想了想自己好像忘了在md5外面加上引号,于是修改成了:
‘ union select ‘…

最大限度精简了语句,也利用上了原本自带的单引号.顺利通过.

SeSSxploit

这道题其实说难不难,由于提供了全套的源代码,所以只要阅读并理清思路就好。

从代码中可以明显看出服务器的php打开了register_global的开关。这个东西在php5.3已经被废弃了,效果是将所有get,post什么的参数都注册为全局变量。这也就提供了一个hack内部变量的接口。

由于要求是将Data[‘level’]的值修改成八,hack无疑从Data入手。不明觉厉的是,我用get提交Data=8之后,竟然直接就过了。接下来实验了一下,不管提交Data=什么都会被注册到level那里,弄得我很困惑。如果有人弄明白了一定告诉我。

Step by step

这道题似乎挺丧心病狂的,我开始做的时候查看了一下数据,只有13个人通过了它,而且上一个通过的记录已经是在三年前了……

第一个登陆框,一开始我以为是sql注入,多番尝试无果。仔细想想,没有错误显示,如果要sql注入的话只能基于时间盲注,搜索量似乎有点大。毕竟对于任何信息一无所知。

然后在胡乱尝试的过程中,发现输入guest和admin作为账户的时候,提示是密码错误而非平时的账号密码错误。无疑证明这两个账户是存在的。

admin/admin尝试未果,guest/guest一遍成功。只能说永远不要忘了最简单的弱口令逻辑错误。

登陆进去以后,根据它是提示可以看到,用setup和admin登入可以创建新账号。

用setup登陆提示,setup账户被config.php禁用。访问config.php显示空白。

在登陆进去的界面把secure后缀去掉,发现可以看到LeetSS目录下的所有文件列表。在readme文件夹可以看到leetSS的一系列信息,不知道是否有用。

明显有用的一个文件是:basic_functions.inc,一个完整的php函数文档。

观察secure页面的源代码,找到如下一句被背景图片覆盖的“/home/www/net-force/challenge/level407/LeetSS/secured/userpages/193715251C371040.inc”

尝 试可以得知,该文件夹无法访问,只能访问该.inc文件。这个似乎就是访问secure出现的页面的源代码。 用basic_function.inc当中的SimpleEncode函数对admin加密,发现加密出来的结果为:1816112D1A163840。与193715251C371040的格式相当接近。 尝试加密guest,果然就是193715251C371040,于是可以猜想另一串数字就是admin的网页。

访问该网页,没什么有价值的内容,大致是admin的密码就是我们需要的最终答案。

尝试加密setup:1C3615341D170040。访问对应网页,找到一个setup/,和setup的密码setuppassword

考虑到denyAccessToSetup这个变量控制了setup是否可以登陆。可能能通过get方法注入该参数。很不幸,尝试在post参数中注入失败。仍旧无法登陆。

<b>Notice</b>:  Use of undefined constant user - assumed 'user' in <b>/home/www/net-force/challenge/level407/LeetSS/secured/userpages/193715251C371040.inc</b> on line <b>3</b><br /><br />

将注意力放到secure页面上面这句话当中,显然在这句话中使用了一个未定义的常量,而php自动采用了xxxx.inc当中定义的那一个。

回忆在xxxx.inc当中看到的, $username = $_SESSION[$sessionDataName][user][“name”]; 这里的确有一个定义的常量,可以猜测它是在登陆时定义的。

由于这里产生了作用域的问题,可以考虑能否用一个更高优先级的user覆盖掉另一个user。寻找无果。

考虑phpsessionid注入的方法。几次登入登出查看PHPSESSIONID,恐怕其并非可以注入。

简单来说,其实我还没搞定啦。

Training - Can you see me?

net-force上的stegano入门题, 查看反白后知道有password.gif这样一张图片,下载后cat得到密码

Go Holland Go!

不要想复杂了, 其实是跟色弱测试差不多的东西

Another picture!

xxd拉到最后看见二进制串, 然后就没有然后了

Words, words, words…

The password that You Need for the challenge page is Again, 跳过三个单词读即可

Nice colors eh?

用stegsolve打开,查看其颜色通道组成的信息, 会发现一个单词: aapjes

Just a flag…

首先解析这个ico,发现里面藏着zip文件, foremost之. 随后发现zip有密码, 一开始以为是假密码…结果发现是真的,fcrackzip之, 很快就出来了

Learn See Become

题目这三个单词的首字母缩写,是LSB

How good are your eyes

最近一段时间做了不少netforce上steg(隐写)方向的题目,感觉在这方面的功力有一点长进.然而碰到题目还是磕磕绊绊,只能说学无止境.等我真的能在这个问题上才思敏捷的时候,再作文聊以总结吧.这次只说这一道题.

题目给了一张几乎空白的图.用力辨识的话能勉强看到上面有一些像素点不是白的.根据一贯的风格,毫无疑问题目就是从这里下手的了.

用PIL写了个程序读出了所有不是白色的像素点和它们的坐标.看了看却没什么头绪.不像是能拼凑出字符串的样子.再仔细观察发现,像素点的RGB值总是一个(250,70,*)的风格,几乎可以确定相同的前两位是无用的.于是关注第三个通道.发现可以把它们重组成一个10~50的等差数列.

虽然重组之后仍然看不出什么,但是无疑已经走在了正确的方向上.像素点的rgb值估计不太可能还隐藏了什么信息,于是开始考虑坐标中是否隐藏了什么信息.

接下来就是不断的尝试了.终于发现像素的x和y值相减得到的是可读字符的ascii值,根据刚才的顺序排列,恰好可以得到一个形如GoodEyes的字符串.

到这里已经几乎可以知道答案了,然而最后某一个字符是不可见字符,其ascii值是3.顿时让我陷入了困惑,不知道该怎么办.根据flag一贯的风格,常常用长得像的字符进行替换以混淆视听,然而几次改换提交仍是无果.终于想起来,3和e虽然方向不同,但勉强也可以说长得像,果然这就是最终的flag了.

Did you try it 100x?

010editor查看可以发现在bmp图片中携带了大量的额外信息, 再考虑标题,不难猜测到需要将其长宽放大.修改到0x64(100)的时候刚刚好

Ancient Voices

一张金字塔的图片,用pngcheck检查发现cHRM块似乎存在问题,查了一圈,这个块很没存在感,所以也没多少解释它的作用的文章.

但它在这张图片中的存在确实很突兀,尤其是那长得离谱的长度….

于是乎切出来,存成文件后file一下,发现是mpeg文件,可以直接播放:tutankhamen. 根据题目来看这应该就是答案了…然而问题来了,我究竟应该提交哪个版本哪种语言的图坦卡蒙….

我到现在还不知道…看了forum我知道了,第一个字母不能大写,英文…. tutankhamun

利用DNS协议进行信息获取

Posted on 2015-02-12

Dns协议简述

DNS协议是什么无需赘述,对于域名的访问需要先通过DNS协议,在DNS服务器上获得相关的信息。

要通过dns协议获得信息,首先需要了解的是信息的在dns服务器上的组织方式。

信息在服务器上被组织成条目的形式,按记录类型分类。比较主要的有A,MX,SOA,NS等类型,具体可查看域名服务器记录类型列表

A

IP地址记录,即我们最常使用的域名->ip映射。

MX

邮件交换地址, 说明某个后缀(@后面的部分)代表的邮件该查询的服务器(以域名表示)。同时会附带其优先级.

NS

名称记录服务器,它将某一个DNS zone(域名的某个特定子集,往往是特定后缀,如*.abc.com)委托到了另一个权威服务器。大型的局域网为了与外部互联网隔离,往往会使用private DNS,可供内部域名使用。再对外注册后,便是对本DNS zone的权威服务器。

PTR

指针记录,通常用于反向DNS查询,当然不必对此抱有太高的期待,ip->域名的映射往往不是那么简单就能搞定的。

CNAME

某个域名的别名,类似于c++中的引用。将一个域名指向另外一个域名。

SOA

指定该DNS zone的权威信息,包含主NS,管理员的邮件地址,和一些其它信息。

dig 命令

与DNS有关的重要指令有dig和nslookup,个人认为dig的形式更优雅易用一些。

其形式为:dig [@DNS_Server] domain_to_query [-t RECORD_TYPE]

默认情况下会采用本地的/etc/resolv.conf文件中的dns服务器地址,可用@指定,如dig @8.8.8.8 baidu.com便是用google的dns服务器来解析baidu.com这个域名。当然,这个ip正常手段是访问不到的。

使用-t可以指定查询的类别,即上面所说的A,NS,PTR等等。

还有另外一些用于控制输出格式和内容的选项,可以在manpage当中找到。通常以+开头,如+short可以输出最简短的结果。

Dns域传送漏洞

所谓域传送漏洞, 指的是private dns配置不当的情况下,主服务器和备份服务器之间传送数据的协议可能被外部利用,使得入侵者可以轻松获得该dns zone的全部网络拓扑信息。

nslookup在linux发行版中(至少在我看过的kali和ubuntu两个版本当中)都像netcat一样,提供了一个去掉了危险功能的阉割版。查看manpage可以看到大段的not implemented.这也是选择dig的一个重要原因。

dig当中用-t指定axfr便可进行域传送漏洞的检测,如果存在的话会刷出一大堆DNS记录。

dig @dns.nwpu.edu.cn -t axfr nwpu.edu.cn

上面给出了一个到现在为止都能成功的例子,这个网站的域传送漏洞在乌云上已经能找到三条记录了。

Dns暴力枚举

暴力枚举不是一个很有美感的行为……但往往是很有效的行为。

kali上提供了好几个可以进行枚举的工具,在使用它们之前要记住,效果如何很大程度上取决于能提供一本多大的字典:

dnsenum

感觉这个是最强大的了,输出格式漂亮,把一大票的功能整合到了一起,一键收割,包括之前说到的域传送。

dnsmap

简单朴素的暴力枚举子域名。不过似乎没有多线程

dnsdict6

很奇怪的名字,相当于多线程版本的dnsmap

当然还有别的,不过没用过。

IP反查

通过初始域名->域传送->暴力枚举这样的步骤,应当已经获得了一大批的域名和对应的ip了。接下来的环节是:通过已经获得的ip找到更多的ip。

概况来讲,就是根据已经有的ip获得c段子网地址,再遍历子网中每一个ip,对其进行ip反查,试图获得有价值的隐藏域名。

反查是最关键的一步。上面有说到可以通过PTR记录反查,不过这样的反查成功率不高。实测比较好的一个方案是通过bing搜索引擎的ip:a.b.c.d功能。比较拙计的是,这个功能对于大陆查询者来说是禁止使用的,只能挂代理。如果不想挂代理,也可以使用aizhan,不过它的准确率似乎比较低。

Emacs 环境搭建

Posted on 2015-01-31

从晚上八九点开始,一直折腾到凌晨五点出头,总算收获了一个令我满意的emacs.
winkar_emacs

让我来自己理一理,我究竟都装了些什么奇奇怪怪的插件.

概述

emacs的插件安装最麻烦的一点,就是通过melpa或者其它方法安装了之后,仍然需要在.emacs文件当中进行配置来开启,弄得我总在安装了某个插件之后陷入它为什么没启用的困惑。

Evil

evil是vim模拟的插件,作为从vim turnto emacs的人,觉得没必要再从头去学一套全新的,而且据说还不如vim的编辑器操作方法了。全心全意把emacs当操作系统用就是。

不得不说evil的安装给我带来了很大的麻烦,不知为何,用melpa安装总是失败。直接通过git源安装也并无分别。

一直知道evil有undotree.el的依赖,但是以为emacs的包管理会自动安装的(要不然为什么叫包管理啊)。貌似本来也的确应该会的,但我手动安装了undotree之后,evil就能正常使用了,不禁让人对这一点产生了疑问。

与之相关的还有evil-jumper,evil-leader.
其中evil-jumper在emacs中模拟vim的跳转栈的行为,可以使用C-o,C-i进行跳转。
evil-leader则是模拟vim中leader-key的行为,放在emacs当中,足以使ctrl使用的频率大大下降了。

还有evilnc-commenter插件,类似于vim当中nerdcommenter,便于在不同语言的文件当中方便地切换注释。

Helm

总体来说,helm是一个类似于vim中ctrlp,sublime中goto-all的插件。是对一个列表的fuzzyfind。

这个列表可以是很多,比如imenu提供的taglist,projectile提供的工程文件列表,emacs本身的buffer列表,emacs的M-x的命令列表等等。非常实用的插件。

Auto-Complete

尝试过company-mode,不知道是不是我设置失误的原因,手感相当差。于是乎还是用ac。

暂时使用的语言主要是python,于是乎安装ac-anaconda-mode作为auto-comlete的backend,补全的效果不错,也附带了跳转的功能。

Smartparens && yasnippet

感觉sublime给我最好的体验之一,就是自带对于括号的补全和一些snippets。

不过装了插件之后的vim和emacs倒是也能达到相同的效果。

Emms

这个插件很有意思,它实际上是一个通过emacs调用其它多媒体播放器后端来播放各种多媒体格式的接口。默认的情况下应该是使用mplaer来看视频,其它的我倒是还没仔细研究。

今天尝试着用它试着看了看优酷上的视频,觉得实在是很有意思。

spacemacs

最近几天在emacs的配置上有点尴尬。功能已经差不多了,然而界面的美化……

所以我又启用了当初引领我走上emacs道路的spacemacs,总算它的功能和那什么……界面,都是不错的。于是乎……短时间不会再多去加别的插件了吧……大概。

WeChall Journal

Posted on 2015-01-24

期待已久的寒假,总算可以(比较)自由自在地做自己想做的事情了。

PrimeFactory

这道题,寻找一百万以上的素数(并且要求其各数字和也是素数)。乍看之下我以为需要很大的计算量,甚至犹豫了一下要不要用C写。不过还是先决定用python尝试一下。

判断素数的方法我使用的是linux提供的factor,当只能分解出一个数字时便是素数。
事实上这个位置的素数还是相当密集的,仅仅在一百万出头一点点就找到了所需的答案。

import subprocess as sp

t = 1000000
def isPrime(x):
    t = sp.check_output(("factor %d" % x).split())
    if t.split()[1] == str(x):
        return True
    return False

while True:
    t += 1
    if isPrime(t) and isPrime(sum([int(x) for x in str(t)])):
        print t

Get Sourced

简单查看html源码就能解决问题。不过答案并不在我一开始想象的地方。

Stegano I

在bmp的最后嵌入了密码。xxd,strings,或者随便什么命令。

Crypto-Caesar I

都告诉我是凯撒密码了……用tr命令解决

echo "VJG SWKEM DTQYP HQZ LWORU QXGT VJG NCBA FQI QH ECGUCT CPF AQWT WPKSWG UQNWVKQP KU UDCJRKRJUROQ" | tr [A-Z] [Y-ZA-X]

WWW-Robots

流浪人,如果你看到robots.txt……

Ascii:

与其说考验知识水平,不如说考验对于这些简单编码的处理速度吧。

a = [84, 104, 101, 32, 115, 111, 108, 117, 116, 105, 111, 110, 32, 105, 115, 58, 32, 99, 98, 104, 108, 100, 105, 110, 110, 111, 110, 109, 111]
s=""
for t in a:
    s+= chr(t)
print s

Encoding: URL

urllib.unquote("%59%69%70%70%65%68%21%20%59%6F%75%72%20%55%52%4C%20%69%73%20%63%68%61%6C%6C%65%6E%67%65%2F%74%72%61%69%6E%69%6E%67%2F%65%6E%63%6F%64%69%6E%67%73%2F%75%72%6C%2F%73%61%77%5F%6C%6F%74%69%6F%6E%2E%70%68%70%3F%70%3D%64%65%64%67%61%72%73%69%70%70%64%62%26%63%69%64%3D%35%32%23%70%61%73%73%77%6F%72%64%3D%66%69%62%72%65%5F%6F%70%74%69%63%73%20%56%65%72%79%20%77%65%6C%6C%20%64%6F%6E%65%21")

说得太直白……

Training:Encodings I

比起上面这道,这道就隐晦多了。
对一大串二进制代码的直接反应,是每八个一组形成翻译成字符。然而照做之后解码失败。
题目中的提示在于“English”,英文字母所用的ascii字符只占用七个bit。而计算总长度发现不为8的倍数而为7的倍数。

t="101010011010001101001111001101000001110100110010111110001110100010000011010011110011010000001101110101101110001011010011110100010000011001011101110110001111011111100100110010111001000100000110000111100111100011110100111010010101110010000010110011101111111010111100100100000111000011000011110011111001111101111101111111001011001000100000110100111100110100000110010111000011110011111100111100111110100110000111100101110100110010111100100101110"
print len(t)

def ec(t):
    l = len(t)
    for i in range(l/7):
        yield t[i*7:i*7+7]
s=""
for c in ec(t):
    s+= chr(int(c,2))
print s

Training: Programming 1

这道题无疑是不难的,简单的编程序收发就好了,然而……
用python requests跑,不停看到“please use cookie in headers”。
于是乎我把header当中能加的东西都加了一遍……直到跟浏览器的请求完全相同,却仍旧不能看到正确的结果

后来我尝试了网上的方案,用ajax。不得不说虽然我不太会js和jquery,但是这个方案的确比我的要方便得多。直接在chrome的控制台输入即可。

$.ajax({
url: 'http://www.wechall.net/challenge/training/programming1/index.php?action=request',
type: 'get',
dataType: 'text',
success:function(data){
var newUrl="index.php?answer="+data;
window.location.href=newUrl;
}
});

到这里已经可以获得正确的结果了。然而我还是想知道python的程序出了什么问题。
在某次退出重新登陆的时候,我取消了wechall那个锁定IP的选项……然后就顺利得出了正确的结果。
只能说无语凝噎。

import requests as r
url = "http://www.wechall.net/challenge/training/programming1/index.php?action=request"
cookies = {"WC": "×××××××××××××"}
resp = r.get(url, cookies=cookies)
ans = resp.text
print ans
resp = r.get("http://www.wechall.net/challenge/training/programming1/index.php?answer=%s" % ans, cookies=cookies)
print resp.text

Training: PHP LFI

LFI这个奇怪的单词……我不知道L是什么,但FI是file include没错。看到了题目也进一步确认它就是文件包含漏洞的利用。

提供了整个页面的源代码,但并没用上。
另外提供了错误信息,看着它足以下饭了。

既然已经给出了答案的位置,直接访问index.php?file=../solution.php
错误信息中,提示找不到文件”../solution.php.html”

于是很明显,需要尝试过滤掉后面的”.html”
利用nullbyte注入,访问index.php?file=../solution.php%00
成功了,但是仍然提示找不到”../solution.php”

访问index.php?file=../../solution.php%00,完成。

PHP 0817

算是出题人的蓄意恶作剧吧。

看起来比上一题复杂,我以为是要用到nullbyte和php的字符串与数字转换的隐式规则。

答案是,php的switch对于条件的判断宽松得令人发指……

我承认我之前不知道这一点。

Training: Crypto - Substitution I

单表替换密码,quipqiup

我已经懒得手动做了。

Training: Crypto - Caesar II

又是一个凯撒加密,准确地说是移位密码。只不过其空间为ascii的26-128

所以其实做法也是一样的,遍历一下所有可能性输出,扫一眼哪些看起来长得像就可以。

Training: Regex

正则表达式基础……分成了好几个关卡

  1. 只匹配空字符串:
    /^$/;这一步学习的是匹配字符串开头结尾的两个符号

  2. 只匹配wechall:
    /^wechall$/;这一步是简单的匹配

  3. 匹配特定文件名的图片后缀:
    /^wechall4?\.(?:jpg|gif|tiff|bmp|png)$/;稍微复杂一些的匹配,注意它会提示你不要使用捕获分组

  4. 同上题,需要对文件名添加捕获分组:
    /^(wechall4?)\.(?:jpg|gif|tiff|bmp|png)$/

Training: MySQL I

基础的SQL注入,admin' or ''like'

Training: MySQL II

与上一题本质上相同,但这次的验证过程更为复杂:根据username取出结果,拿第一组结果中的密码与提交的密码的MD5比较,相同则视为登陆。

注意到成功登陆时,使用的是该组结果当中的username项,而非原来的username。从这里可以看出该题应当不需要二次SQL注入。

提交username='union select 1,'admin','e10adc3949ba59abbe56e057f20f883e; password=123456即可,注意到其中e10adc3949ba59abbe56e057f20f883e为123456的MD5hash结果。

Training: Register Globals

利用php的register global选项,该选项将所有提交的参数注册为全局变量。
这个功能在php中已经移除。

查看源代码发现,其用$login这个变量来控制是否登陆,且只要$login[0]==admin,就能完成任务。

php的另一个特性是,可以通过get参数提交数组。

因此,在url后加上?login[0]=admin即可

Limited Access

这道题关于.htcacess,我对于它不熟,应该说,对于apache都不熟。让我自己编写这个配置文件肯定没办法,然而……我只需要看懂就可以了。

显然能登陆的用户信息在.htpasswd里,这个文件访问不到。于是乎……看了看下面写的限制,貌似只对get进行了限制,那就简单了。直接用post查看该界面,就能通过了。

Limited Access Too

这道题跟上一道题基本相同,我很无语。它的改动在于额外禁了一系列的http method。然而http的各种奇葩method太多,杀之不绝啊……

curl -XTO http://www.wechall.net/challenge/wannabe7331/limited_access_too/protected/protected.php

记得把cookie也一起提交上去。

你问我TO是什么?我估计是用不到的,所以我也没查。

Enlightment

这道题……我一开始没做出来是犯了一个很大的错误。

由于经常用到把binary string转换成字符串的功能,其中需要每八个一组迭代一个字符串,而我之前竟然都是用slide_windows写的,觉得自己实在是蠢得不能再蠢了。

总之……现在是行了。

这道题的point在于,RGB三种颜色要怎么混合。一开始我想得有点复杂,把它们按照一般的RGB转灰度的公式处理……结果似乎是想复杂了。

其实只要把三个二进制串OR一下就可以了。

这只是第一步。第二步会给另一个二进制串,这个倒是可以直接转换成字符串。

第三步是另外的三个二进制串。这次不是OR一下,而是XOR一下。答案就有了。

r = "00000000011000000110000000000000000000000100000000010000000000000111000000100100001000000110100100010000000000000010100101100101011001000010000000000000000000000101010000000000011000100010000100101100011000000101000000100000001010010000001000000000000000000000100100000010011101000010000101000000011000010100001000010100011000010100011000100000001000000000010000000010000101110000010101101000001010000010000001100100000000010000000001000010001011100000000001110100000000100010000000010100011000000100000100100000000001100010010001011000011101000010000000100011011101000100000100100111010001000000110000000000010001100010001100100000011101000100100001100001010100000100010100110010000010010000101000000000001000010000000000010000001100010010000100110000001100000001000000010001001000000000000000100001000000000010000000110001000100000000000000000000001000000011000000000001000100000001000100000000000100000011000100000000000000010011000000000000001000000000110100001000000100000001000000100000001000000011000000000001000000000000000100100000000100010010000000010000001000010001000100000001000100000011000000010001001100000000000000010001000000000000000000010000000000000000000100100001000000000011000000110001000000000011000000001000000000000000000000000000000100010011000000100000000100010000000000110000000100000010000100110000000100000010000000110000001100000001000100100000001000000001000000010000001000000000000000000000000100000010000000010000001100000001000100000000001000000001000000010000000010000000100000100000001100000001000000010000000000000000000000010000001100000000000000110001001000010001000100000000000100000000000000000000001100000001000100110001001100000000000100110000000100000011000000000000000100000001000100110000000100000011000000000000000100000000000100000000"


g ="01000001011010000010000000000000000000000000000101100100000000000100000000100100010001000000010000100010000000000011100101000110011000000000000000100101010011000010000000000000001100110100100101100000001001010000000001000000001010000010011001100110001000000110100001000100010000000100010100110010001000000010000000110000001010010110000000000101000000010000100000001000010101110010000101000100010011000010000001000000001001100000000001100000000011010000000000010000011011100010000001100000001000000100010000000000011011000100010100010000001100000000000000110000000100000110000101100000011001010000110000000000010001010100010100100000000001000110100000000101011100100110010000000000000011010000000000110000000000000001000000110000000000000011000000010000000000000001000000010000000000010001000000110000000100000001000000000000000100000001000100110000000100000011000000110000001000010010000000010000000100010000000100110000000100010010000000010000001100000000100000000010001000000011000000010001000100000001000000100000001100000001000000010000001100000001000000000000000100000001000100110000001000010011000000100000000100000011000000100000001100000011000000010000000100000011000100010001001100000010000000000001000000000000000000000100000000100011000000100001001100010010000000110000001000010001000100000000000000000000000000100001001000000001000000100000000000000000000100010000000100000010000100100000001000000011000000000000001100000000000000010000001000010011000100110000000000000011000100010000000011000000100000010000000100000000000100010000001100010001000100000001001000000011000000100001001000000011000000000000000100000010000000110000001000000010000100100000000000000001000000100000001100000000000000110000001100010001000100110000001000000001000000110000000000000000100000001000"

b = "01000001010000000110000100100001001000000000100001000100001000000101001101100001011000010100000101100011001000000110000001001101000100010000000001100011001000110011010000100000010100110010111001001001011000010110010000101000011010000110110000100001000000000010000000101010000100000010010100010000000001000001001101000100000000000110110001000110000000010000010100001000000000010110010101100100011000000010000000110000010011110010000001000101010010100010000001000100000010110010000000100000000010000010000000000000011001000110000001101000001000000000000001000000001000000110000000000101000001010010100000100000001001110000111000100000001100000000100000000100000100100000010000001010000001000000101000010000000100010010000000000000000100000000000000000000001100000010000000100000000100000010000000100001001100000010000000110001001100000010000000000001000100000010000000010001000000000001000100100000001100010000000000000000001100000001000000100000000100000000100100001000000000000000000000100000000000010001000000110000000100010010000100110000001000000001000000100001001000000011000000110000001000010011000000000000000000000010000000110000000000010011000000100000001100000010000000110000000000000000000000110001001100000001000100000101000010000000000000010001001000010000000100010000001000000010000000110000001100000001000000010000001000000011000000110001001000000011000000000000001000010010000000100000000100010001000100110000000000000001000000100000001000010010000100010000001100000011000000100000000001010000001000100000000000000011000000100000000100010010000000110000000000000011000000010000000100010010000000110000001100000011000000100000001000000000000100010001001100000010000000010000001100000000000000000000000000000010000000000001001000000000000000000000001000000000110000001010"


def bin2str(t):
    s=""
    for i in range(len(t)/8):
        s+=chr(int(t[i*8:i*8+8],2))
    return s

s=""
for i in range(len(r)):
    s += str(int(r[i]) | int(g[i]) | int(b[i]))

print bin2str(s)

# stage 2

s = """01001100011010010110011101101000
00110111010111110100110001100101
01110110011001010110110000110010
00101110011100000110100001110000"""

s = s.replace('\n','')
print bin2str(s)

# stage 3
r = """001111111000110110000110001011110011010010000000
110100111001010001010101010110000000101111110010
011100010011110001101000000010100101010101011110
100101001001100000100000001000010000111001010110
110011000110011011000010101010010001100111011110
011011011100101001101100100000110001010101001111
100100100100100011000000000001100101001100110000
110111000000001101010101100110101110000100100011
100011000100011010001011011011101101110000001000
110001011100000110011100110010001010100110010100
001111001101000001001111000111010100000000100000
110010000110110110010101011101101101110101111110
101110110110000101100000000100000000100110010100
100111000100010000100111001110011000000010100110
101111101010000100001111101110110100110100000010
000101110100010010001001100001011111101011001000
110000001001101011000100010101100111000010000110
110010111011001100000001000100001000010010000010
10011001010000100011100101011110"""

g = """001000111110001110011011010011010000001011011110
101000001110000110100010001001011111010110011011
100001010100011000010001010110010010100110000010
101010110011011101000111011100100000010000111010
001110001000101010010000110001111100011100100001
000110101001011000011110001000101000011001000111
111000011010010010110000001000010001110100001000
100000011000100011010001101011000001110101000100
101110110000001101001001110110110011011110011101
101011110000100100110001000100011000000001011001
000000010010011110000100100110100001000101000100
010101010101001000000000011110011101010011011001
110100001000100000000110001101111010000001000000
111100101010100001001000001101110001101001001001
110001111101001100001100001000100100001010010000
110000010011000111001100001110101000011000111100
001100011010011110100010010110000000110111111101
111000010000100110011100110000001110110000111001
10000100101100011100101011101100"""

b = """010010000001110001110100000100100101101000111011
010111100010110111011010001100101010110001000101
110101000000100000010000001101000001010010101000
000000001010001001101101000101000111100000001001
100101011001100001110011010011101001011010011010
000001010011100101010010110010001110000000101000
000001001000010000010001010100110110111001000001
001100101111111010100100010001011001010000001000
010000100010100110100110100101011000100111110000
010010101010010011000010101101100100001010100100
010100111001000011101011111000010011111000010110
101100110001000110111011000000100000001110000101
001011001000000000001011010010101100110010001011
001010101000110100110000010000101111001110001000
000100010000011000100001100101000000010111110111
101110000000000100100000110011010101110010000000
100110010101010000010101001011100001110000001000
000010101100101011111100101000110001101111001100
01110010100000011001011110010011"""

r = r.replace('\n','')
b = b.replace('\n','')
g = g.replace('\n','')

s=""
for i in range(len(r)):
    s += str(int(r[i]) ^ int(g[i]) ^ int(b[i]))

print bin2str(s)

Guesswork

这道题还真是不那么令人愉快啊…

其目的是猜测一个账户的密码。据讨论区所说,可能有非纯猜测的方法,我觉得可能是社工。然而也没有英文的社工库,所以还是猜。

尝试了一些弱口令,当输入wechall的时候,虽然还是错的,但给出的回复有些不同,提示接近了。

我仍旧是猜不出来……然后在别人的提点下:它的账号是wechall,它的身份是个bot……

于是密码是wechallbot.我无言以对。

No Escape

很长的php代码审计,我原以为会是什么很复杂的东西,其实也不过是简单sql注入罢了。

只需对提交的参数做一点小手脚就可以了。

?vote_for=bill`=111;#

Training: Crypto - Transposition I

这道题困扰了我一段时间……

对待置换密码,首先需要根据其长度特征进行判断.该文本的长度为148

factor 148可以看到,其因数为2,2,37

看到这样的因数就知道,需要枚举的情况不会太多了。

无非是4*37,37*4,2*74,74*2这么几种情况。都枚举一下打印出来,看看是否能辨认出熟悉的单词的痕迹就好了。

Training: LSB

事实再次证明stegsolve是个好东西。

拖进去看一看各个通道有什么就好了

Training: RegexMini

一开始以为是php的漏洞,后来发现原来是简单干脆的正则表达式。

当然,是php的正则表达式。

具体可以参考php手册,查看^和$这两个字符究竟能匹配些什么。

其实就是十六个A后面加一个换行符(%0A)就好了。

PHP 0819

这道题涉及到了一个以前没接触过的点。

php里有一个叫做heredoc的东西,用于实现python当中三引号差不多的功能,但语法上似乎更为复杂。

用这个东西便能绕过对于引号的过滤,注入想要的字符串

%3C%3C%3CA%0A1337%0AA%3B%0A
>>>A
1337
A;

Training: Warchall - The Beginning

  • level 0: bitwarrior:

  • level 1: LameStartup:
    通过find找到solution

  • level 2: HiddenIsConfig:
    通过.bash_history找到

  • level 3: RepeatingHistory:
    仍然是在.bash_history中找到

  • level 4: AndIknowchown:
    一个没有权限的文件,但有改权限的权限

  • level 5: OhRightThePerms:
    仍然是改权限的小游戏

我花了很长很长时间去做level6……然后发现只要求输入level0~5的密码。

最后……记得加上逗号

Py-Tong

需要一个程序与提供的程序达成race condition,多试几次就能输出正确的结果了。

#!/usr/bin/env python
# coding=utf-8
import os
while True:
    os.remove('/home/user/winkar/test')
    f= open('/home/user/winkar/test', "a+")
    f.close()

PHP 0815

我自己想不到的hack。

缺失的环节是,传入的参数需要转换成整数。

通常所用的函数是int()或者intval()

然而出于php wtf的atoi转换规则,$s-0足以完成。于是-0就是最短的答案

Impossible n’est pas français

题目的要求是factor一个很大的数字。试着看了看那个数字的长度之后我放弃了正常途径。

我开始寻找是否有api可以完成这个工作。

其实只要提交一个错误的答案,wechall就会告诉你正确的答案。

于是乎……

#!/usr/bin/env python
# coding=utf-8

import lxml
import lxml.html as H
import requests

cookie = {
    'WC': '8429765-12152-0vjRl2XoKWFYAmvh'
}


def get_number():
    number_url = 'http://www.wechall.net/challenge/impossible/index.php?request=new_number'
    resp = requests.get(number_url, cookies=cookie)
    d = H.document_fromstring(resp.text)
    return str(d.xpath('//div[@id=\'page\']')[0].text_content()).strip()


print get_number()

def get_answer():
    post_data = {
        'solution': '1+12',
        'cmd': 'Send',
        'gwf3_csrf': '2XDoWTUR'
    }
    url = 'http://www.wechall.net/challenge/impossible/index.php' 
    resp = requests.post(url, cookies=cookie, data=post_data)
    # print resp.text
    d = H.document_fromstring(resp.text)
    import re
    ar = re.compile(r'"(\d+)"')
    text = d.xpath('//div[@class=\'gwf_errors\']/ul/li')[0].text_content()
    ans = ar.findall(text)[0]

    print ans 

    post_data = {
        'solution': ans,
        'cmd': 'Send',
        'gwf3_csrf': '2XDoWTUR'
    }

    resp = requests.post(url, cookies=cookie, data=post_data)
    print resp.text

get_answer()

Stegano Attachment

xxd一看就知道,提供的jpg图片里面藏了一个zipfile。如果是当年懵懂无知的我,要提取出来还是会很费劲的。

然而现在……

foremost -i attachment.php(这是下载过来图片的名字)

一切尽在不言中

PHP 0818

这道题又一次让我对php这门语言绝望了。

不允许出现数字但又要求与一个数字相等,无非就是字符串与数字转换的规则问题。

一串字母如何与一个数字相等,自然是十六进制。

十六进制的字符串为何能与十进制的字符串相等……那就说来话长了,可以去看一看php中”==” 与 “===”这两个操作符的区别。

强烈推荐,除非故意要留下这么个漏洞,不然不要用前者

Stop us

又一个未涉及过的知识点。

也又一次让我觉得php这门语言……虽说C/C++的“未定义”让人咬牙切齿,可跟php里这种种特意定义出来的bug相比,不值一提

这次是ignore_user_abort,将此选项置false的情况下,客户端中断连接将使脚本执行停止。

一个活生生的事务处理的原子性不能达成的例子。

Are you serial

给出了很多代码,不过也算是有重点。首先是一个标题名,表示可能与php中的序列化函数有关。

然后是一个叫做insecure.inc.php的文件,没几行代码,里面用到spl_autoload_register这个函数。由于php中的register劣迹斑斑,果断去搜索了一圈这个函数的用法。

这个不安全的文件实现的大致效果是,当碰到一个找不到的类时,php会通过注册的函数,自动在include path当中寻找并包含对应的文件。再看一眼solution这个文件大致的思路就拼凑出来了。在cookie中提交一个solution类的序列化字符串即可。

#!/usr/bin/env python
# coding=utf-8

import requests

solution = r'O:15:"SERIAL_Solution":0:{}'

cookie = {
    'WC': '8429765-12152-0vjRl2XoKWFYAmvh',
    'serial_user': solution,
}

resp = requests.post('http://www.wechall.net/challenge/are_you_serial/code.php' ,cookies=cookie)
print resp.text

Training: Math Pyramid

这道题坑人的地方在于故意给你的sqrt,不用它会大大减低难度
a^3/18^.5

Training: Crypto - Digraphs

这道题麻烦的地方是,大小写字母的编码方式是不同的,且标点符号也在编码的范畴之内。因此不能将其转换成普通的单表替换密码。

比较明显提示是,第一个单词的长度,结合该语境,它无疑是congratulations,这样好多字母对应的key已经获得。接下来只要把剩余的每一个单词的密文在已有字典中检索一遍,再根据拼凑出的碎片还原整个单词,再更新字典即可。

事实上凑到最后我还有一两个字母没有确定,不过已经不妨碍了。

HOST me

比较别扭,查了HTTP_HOST之后就知道该在HEADERS的HOST上动手脚,然而不知为何,无论是用requests还是用chrome改header怎么发都提示Wrong Host。

最后的解决方案是在nc里直接发一个最简洁的http报文,就能返回正确的结果了。

GET http://www.wechall.net/challenge/space/host_me/index.php HTTP/1.1
Host: localhost
Cookie: 

AUTH me

对于SSL还是很不了解,这个apache.conf在讲什么……我也是完全当做英文理解的,大致对于一些点去查了一查,并无什么收获。

其实在apache.conf中规定了,client端需要证书才能访问server端,那么证书在哪里呢。就放在/challenge/space/auth_me/find_me/文件夹下(即apache.conf所在文件夹)……

导入浏览器即可

Stegano Woman

给了一个压缩包,里面有两张图片。用各种stegano检测的工具对两张图片上上下下检查了一圈,什么都没有看出来,很是尴尬……

在某次解压缩的过程中(用的是命令行的zip),发现除了解压出来的文件列表外,还额外输出了一大堆东西。现在我已经知道了,输出的这些东西是zip文件当中的备注。

于是后面的过程就是把备注找出来,发现接在stegano字符串后面的,是一大串TAB和SPC.把其中一个当做1,另一个当做0,换成二进制再转换成字符串之后输出即可.

with open('00000000.zip','rb') as f:
    text = f.read()

index = text.find('Stegano')
text = [x for x in text[index:] if x]
text = text[:273]
text = text[9:]
text = ''.join('1' if x==' ' else '0' for x in text)

s=""
for l in range(len(text)/8):
   s+= chr(int(text[l*8:l*8+8],2)) 

print s

Connect the Dots

名字上已经可以看出来把各个黑点(或者白点)连起来能看出一点信息,然而连了半天什么都没看出来.

随后搜索得到结果,原来这里使用的是盲文,难怪….

Training: Baconian

so called 培根密码,我保证这个加密不会是你感兴趣的.寻找工具而非自己编码是更好的方式,只需按大小写将其转换为’A’和’B’,之后丢到这个网站Bacon就可以了.

注意大小写which is A and which is B is important.And 培根密码有两种加密形式,取决于ij 和 uv 是否采取同一种编码

Zebra

这道题本身是不难的,在对图片进行分析之后,不难发现斑马身上的条纹很像一个一维条形码(barcode).接下来便是将其抠出来, 无非是gimp, ps, mspaint之类的工具都能解决.

真正困扰我的是,如何识别出条形码里的内容.我试着根据EAN-13的规则人工识别,惨败.之后在手机上下了APP,仍旧是失败.最终给出结果的是这个网站barcode online reader

Training: Crypto - Substitution II

与diagraph相同, 采用了wechall环境下密码题的”congratulations!”解题法.

这么一大串东西,直接猜测是以congratulations!开头, 替换完之后发现长得的确看起来像那么回事,于是一点点拆解单词,很快就能把原貌还原.

eXtract Me

给了一个zip文件,仔细研究其内部结构发现在zip结束符之后还有额外的部分.顺带一提,这本该是foremost或者binwalk完成的工作,可是它们都检测不出来….

前半个部分,也就是zip文件,一个440B大小的无限循环解压的zip文件,跟它较劲毫无意义.而后半部分导出后是用奇怪的手法层层包扎的压缩包.未统计,可能有那么七八层.

解压的过程中要灵活运用file命令来探知压缩包的格式.已经7z可以方便地解压很多种类的压缩包,虽然还是有那么一些奇怪的类型需要安装对应的软件用以解压..

第一遍解压到最后,结果蹦出来一句话:L0LYouThInkiTSh0uldB3SoEasY? 这已经不知道是第几次被出题者戏耍了.这句话虽然不是答案,但也是有用的.

另一个分岔实际上在解压某一个rar文件时,会给出一大串十六进制, 将其导出为二进制文件,又是一个压缩包,还是层层解压.

到最后又是获得了一个rar文件,然而它有密码. 一开始在这里愣神了,以为是假密码,修改标志位后却提示已经损坏. 总算想起来之前获得了一个字符串,一试果然成功,获得最终的答案

htmlspecialchars

这道题一股蛋疼感.

exploit payload:

test' onclick='alert(123)'

切记不要在chrome下测试…我没有装任何adblock但它还是不弹窗.

可以看出原反XSS代码的主要问题就是没对单引号做转义

查看htmlspecialchars的文档,发现它默认不对单引号做转义,加上ENT_QUOTES参数就可以.

PHP 0816

整理一下整个script走过的路径.

1.检查参数src,如果值不在白名单里,则将值置false
2.将参数hl数组中的值加入highlight列表
3.检查参数mode,如果mode为hl则调用函数载入src参数指定的文件.

虽然我在上面标了一二三,但注意源代码当中,这三者之间并无顺序.

php中foreach是按照数组的赋值顺序遍历的, 关于GET参数的传入顺序我并无找到资料, 也懒得做实验, 根据这道题的结果来看大概也是跟url中参数的传入顺序有关的.

因此只要在白名单过滤之前载入src参数指定的文件就可以.

http://www.wechall.net/challenge/php0816/code.php?mode=hl&src=solution.php

Quangcurrency

读题是很重要的…来把这个题目大概念出来,它是什么?concurrency对不对?又是一道竞态的题目.

只要卡着buy和click,想方设法跑到10个item就可以

cookie = {
    'WC': '8429765-12152-0vjRl2XoKWFYAmvh'
}

def f1():
    requests.get('http://www.wechall.net/challenge/quangcurrency/click.php', cookies=cookie)

def f2():
    requests.get('http://www.wechall.net/challenge/quangcurrency/buy.php', cookies=cookie)
import requests
import threading
import time

import lxml
import lxml.html as H
import re

r = re.compile(r'\w+: (\d+)')

i = 0 
while True:
    i += 1
    print "turn %d" % i
    print 'start click'
    t1 = threading.Thread(target = f1)
    print 'start buy'
    t2 = threading.Thread(target = f2)

    t1.start()
    t2.start()
    t1.join()
    t2.join()

    text = requests.get('http://www.wechall.net/challenge/quangcurrency/stats.php', cookies=cookie).text
    d = H.document_fromstring(text)
    msg = d.xpath('//div[@class=\'box_c\']')[0]
    # import pdb;pdb.set_trace()
    a,b,c  = r.findall(msg.text_content())
    print 'get %s item ' % c

    if int(c)>=10:
        break

    if int(a) < 1000:
        print 'reset'
        requests.get('http://www.wechall.net/challenge/quangcurrency/reset.php', cookies=cookie)

友情提示,它肯定可以跑出来,但它永远不会停下,最好自己确认这个challenge是不是已经完成了.

Yourself PHP

我研究怎么绕过htmlspecialchars花了很长时间,然而得出的结论是这个地方似乎不太能绕过.

后来了解到注入点不在username, 而在$_SERVER[‘PHP_SELF’], 所以….足够仔细的代码审计非常重要.

http://www.wechall.net/challenge/yourself_php/index.php/%22%3E%3Cscript%3Ealert(1);%3C/script%3E

用上面这个url访问即可

The Guestbook

SQL注入.

其关键在于绕过对输入的过滤,当然我的确不知道怎么在有过滤的情况下完成注入,但仔细审查源代码会发现,除了输入的信息之外,ip和sessionid都是未过滤的注入点.

Session id不方便下手,那么ip就是最好的选择

X-Forwarded-For: ',(SELECT gbu_password from gbook_user limit 1));#

构造这样的http header, 再提交message即可将查询到的结果输出.

Crappyshare

仍旧是代码审计,文件包含漏洞…但是你得知道怎么通过文件包含漏洞去访问到solution.php

php 封装协议这篇文章中讲解了一系列相关的知识.

使用file://协议可以令其访问本地文件

Pimitive Encryption

用onetime-pad xor加密的zip文件,通过zip的magic number可以确定onetime-pad的前四位,转换成char输出后发现是3.14

于是该用什么解密就很明显了,下载一个pi之后xor一下,就能还原了.

WinKaR

7 posts
© 2019 WinKaR
Powered by Hexo
|
Theme — NexT.Muse v5.1.4