《Codefest2018 writeup》

本文转载自: github.io
如若转载,请注明出处: https://jianghuxia.github.io/2018/09/03/Codefest2018-CTF/

实在是太无聊了,找了找比赛打,Codefest2018这个感觉跟以往的ctf比赛不同,感觉更偏向代码能力的考查,以下是这次自己做出来的题目writeup,比赛题目一共15道,菜鸡一枚,只做出10道。

Freebies

problem

This one’s simple. Join the Slack channel to get the flag.

这题算是签到题,但也是寻找了好一番,就不放答案了

Fortune Cookie

problem

H4k3r has heard that there is a secret hidden behind this website, but he is confused as to how to get access to it. Can you help him

这题,呃,很简单,该下cookies(说着简单,最后试了半天才发现是admin,不是Admin)

《Codefest2018 writeup》

Who are you?=admin即可

《Codefest2018 writeup》

Typing Master

problem

If you think you have it in you, connect now to 34.216.132.109 9093 and prove your mettle.

You will be presented with a simple typing task which is meant to check your typing speed.

For example, Can you type ‘Z’ 10 times followed by ‘u’ 6 times, followed by the sum of their ASCII values?

ZZZZZZZZZZuuuuuu207

Input Format

Regarding input to the server – The question was designed keeping netcat in mind. Some users who are using other tools/language (eg, , PuTTY, TELNET) to connect to the server please note that they do not terminate the strings like netcat does. If you choose not to use netcat, the message you send to our server should terminate with a trailing newline (‘n’) and nothing else.

nc下,先看看大概是啥样子的

《Codefest2018 writeup》

发现每次访问,要求的都不一样,甚至返回的字符串也不一样,想了想,觉得还是一个脚本的事,需要正则一下即可

脚本如下:

#-*-coding:utf-8

from pwn import *
import re 

conn=remote('34.216.132.109',9093)
text=conn.recv()
print text

result = re.findall(r"'(w)' (d*)", text)
#print result
#print result[0][0]
#print result[0][1]

str1=(result[0][0] * int(result[0][1]))
str2=(result[1][0] * int(result[1][1]))
str3=(str(ord(result[0][0]) +  ord(result[1][0])))
S = ''.join(str1+str2+str3)
print S

conn.sendline(S)
print conn.recv()

运行结果

《Codefest2018 writeup》

最终答案:CodefestCTF{1_s33_y0u_4r3_a_m4n_0f_sp33d}

BooK

problem

It is expected to complete reading a book/novel to pass the course, but the students being clever avoid reading the whole book by going through the summary only. Santosh(their course teacher) comes up with a new idea, he creates a magic book (you can only to next page, that is: you can’t to next page without reading the previous one and so on, and you can only start from the beginning). It is know that the flag is hidden somewhere in the book, so the only way to pass the course is to read the whole book, find the flag. The book has 1000 pages so better be fast. And if you are lucky, you may even find the key on the very first page itself. link to Web_BooK

打开网站,发现如下页面,点击next发现,都是没有规则的url

《Codefest2018 writeup》

没办法,只能简单爬虫脚本写下,源码如下

#-*-coding:utf-8

import requests
import re


url = 'http://34.216.132.109:8083'
page = '/fp/'
s = requests.Session()

counter = 0
while (True):
    counter += 1
    r = s.get(url + page)
    page_text = r.text
    print page_text
    page = re.findall('action="(.*?)"', page_text)[0]
    print page, counter

运行下

《Codefest2018 writeup》

Access Denied?

problem

A school IT staff manages access to secure files by the method of access code. You are required to give your name and the access code, and the program will give out secret information.

It checks whether you already have an access code, generates new random one along with a new user ID alloted to the user, if that user is not found locally on the system. The access codes are known to have random expiration time (don’t know what goes on in their minds!), so don’t be surprised if you generated an access code just seconds ago and next time the same access code doesn’t work.

Johnny decided to into the IT room and copy the program into his pendrive. You can find it here.

Can you get the secret information out from the program? The service runs on 34.216.132.109 on port 9094.

Constraints

User ID / UID will be a positive integer

这题给了个school.py

#-*-coding:utf-8
import random
import user_functions

user = raw_input("Enter your name: ")

if not user_functions.exists(user):
    # generate a code

    count_ = user_functions.generateID(user)%1000    #User ID/ UID in the table is always positive

    generator = "xorshift"
    random.seed(generator)
    count = 0;

    for ch in user:
        ra = random.randint(1, ord(ch))
        rb = (ord(ch) * random.randint(1, len(user))) ^ random.randint(1, ord(ch))

        count += (ra + rb)/2


    code = 1

    for i in range(1,count+count_):
        code = (code + random.randint(1, i) ) % 1000000

    final = random.randint(1,9) * 1000000 + code

    #store it in the database
    user_functions.store(user, final)

else:
    #if user already exists, fetch access code
    final = user_functions.get_code(user)

code = raw_input("Enter your access code: ").strip()


while True:

    if code.isdigit():
        if (int(code) == final):
            print "The flag is " + user_functions.get_flag(user)
            exit()
        else:
            print "Incorrect access code"
    else:
        print "The code must be an integer"

    code = (raw_input("nPlease enter the code: "))

    print "n###############################################"

乍一看好像挺复杂的,其实不然,只需要爆破即可,简单分析下

起始变量count 是由我们输入的user确定的。如果我们每次测试时都提供相同的user,那么最终count变量也都是不变的;而count_变量嘛,虽然不知道到底是什么嘛,但是模1000得到的结果只可能是[0,999];而code呢?由于code种子xorshift生成的,我们可以根据count_遍历code。只需要稍微改改给的school.py我们就可以暴力跑出答案。

核心代码其实也就是下面这个:

for i in range(0,1000):
    count_ = i

    # the seed is always the same
    generator = "xorshift"
    random.seed(generator)
    count = 0;

    for ch in user:
        ra = random.randint(1, ord(ch))
        rb = (ord(ch) * random.randint(1, len(user))) ^ random.randint(1, ord(ch))
        count += (ra + rb)/2
    code = 1
    for i in range(1,count+count_):
        code = (code + random.randint(1, i) ) % 1000000
    final = random.randint(1,9) * 1000000 + code

完整代码如下:

#-*-coding:utf-8
from pwn import *
import sys

list_code = []
user = 'jianghu'

for i in range(0,1000):
    count_ = i

    generator = "xorshift"
    random.seed(generator)
    count = 0;

    for ch in user:
        ra = random.randint(1, ord(ch))
        rb = (ord(ch) * random.randint(1, len(user))) ^ random.randint(1, ord(ch))

        count += (ra + rb)/2

    code = 1

    for i in range(1,count+count_):
        code = (code + random.randint(1, i) ) % 1000000

    final = random.randint(1,9) * 1000000 + code
    list_code.append(final)

print list_code

con = remote('34.216.132.109',9094)
con.recvuntil('Enter your name: ')
con.sendline(user)

for i in list_code:
    text = con.recv()
    if 'flag' not in text:
        con.sendline(str(i))
    else:
        print text,i
        sys.exit()

运行结果如下

《Codefest2018 writeup》

最终答案:CodefestCTF{1_s33_y0u_4r3_a_m4n_0f_r4nd0mn3ss}

It’s Magic

problem

Repair given corrupted file to get the flag. download file here

下载完毕后,拖到winhex里,拖到尾部发现FFD9,尝试改文件头,发现无效

《Codefest2018 writeup》

遂尝试网上搜索在线修复受损图片,找到一个工具网站

修复完成后,打开即有flag

《Codefest2018 writeup》

最终答案:CodefestCTF{mAgic_byTes}

Hidden Agenda

problem

Just before getting caught in Russia, MI-6 agent John Stegwal sent a mail to MI-6 containing two visually similar images. It is possible that the images contain information on how to access his findings. Can you find the message he sent?

给了两个jpg文件:image1.jpgimage2.jpg

先用StegSolveimage1.jpgimage2.jpg来次xor,发现有个二维码的痕迹,保存为solved.bmp

《Codefest2018 writeup》

solved.bmpimage1.jpg再来一次MUL,得到一个可扫的清晰二维码

《Codefest2018 writeup》

扫出来是个网址https://..com/file/d/13chbULOlKaOM_jI8_RaxECZ0xzJUg7Y4/view,打开后,有张图片,下载下来,打开后可以看到清晰的flag{字样,然后,没然后了,这张图片只有flag{(那时候看到flag,开心极了,贼坑)

《Codefest2018 writeup》

没事,我吃柠檬。谷歌了下,找了找有关jpg图片隐写,找到了个jsteg,哟,试试

先试试image1.jpg,试出东西来了

《Codefest2018 writeup》

得到了个flg.exewinhex看下,没看懂是啥

《Codefest2018 writeup》

file下,发现是个MP3

《Codefest2018 writeup》

改后缀名,听了听,这是鸟叫声?exm?拖到Adobe Audition CC2017试试,查看了下频谱图

《Codefest2018 writeup》

得到最终答案:CodefestCTF{0b5cur17y > 53cur17y}

Thunder

此题给了个流量包thunder.pcap,包不大,分析发现好几个flag.jpg,但是都是不完整的。

《Codefest2018 writeup》尝试根据jpg文件的文件格式来拼图。先导出http对象,删除重复的。此题有个坑点,不可以按照分组序号的大小来拼,必须按照TCP流所显示的时间依小到大排序,然后拼好即可。

《Codefest2018 writeup》

人懒,写了个bat脚本1.bat

type flag*.jpg>>all.jpg

以下是all.jpg

《Codefest2018 writeup》

得到最终答案:CodefestCTF{AP_is_amazing}

Polyglot

problem

Chetu writes code with weird whitespace, and nobody knows why. He uses his own C interpreter, which is probably the only thing that can handle his absurd code. He insists its more secure this way. Since no one ever believes him, he demonstrated his technique on this vulnerable code. Can you get the flag?

这题贼有意思,贼好玩。题目给了两个文件,但是做这题,我只用了c代码的文件,另外一个elf都没看。

首先我们看看c

《Codefest2018 writeup》

会发现,这些数字排序,怎么都是空那么多格子的呢?奇怪,但是突然想起了写脚本时,会因为空格和tab混淆而报错,下意识看看这些空白字符是由什么构成的。Notepad++有个功能

《Codefest2018 writeup》

果然,这些空白字符是由不同的空格字符和制表符组成。尝试先用脚本读读

《Codefest2018 writeup》

果然,猜想是正确的,那么现在需要提取下这些空白的字符。想到了正则表达式,其中s表示只要出现空白就匹配。但是匹配完后有什么用了?随即想到有没可能是0,1替换,到时候来个二进制转换ASCII可见字符。尝试一波,先匹配试试,然后‘t’替换成1‘ ’替换成0,得到了想要的答案

《Codefest2018 writeup》

最终答案:CodefestCTF{sP4c3S AnDtAb5}

Intercept

problem

Garry encrypted a message with his public key and mailed it to Monika. Sure Garry is an idiot. The intercepted mail is given below as seen from Monika’s side. Decrypt the message to get the key. interceptedMail.eml

下载文件后,发现eml中存在zipbase64解码下

《Codefest2018 writeup》

有两个文件,flag.enc是密文,但是私钥哪去了呢?其实在下面那个文件里。

《Codefest2018 writeup》

其中Public_Key_Encryption_.docx实际上是是个压缩包,winhex下看到了PK的头

《Codefest2018 writeup》

改后缀名,解压。寻找一番没找到私钥。最后才发现,在解压文件中wordmedia,存在三张图片

《Codefest2018 writeup》

其中的image1.png的尾部存在私钥《Codefest2018 writeup》

那么,提取出来,保存为private.pem

《Codefest2018 writeup》

额,openssl解密下,执行命令openssl rsautl -decrypt -in flag.enc -inkey private.pem -out flag.txt

《Codefest2018 writeup》

最终答案:CodefestCTF{kristeinStewart_is_5EXY}