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)

1535766037090

Who are you?=admin即可

1535766076578

 

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, Python, 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下,先看看大概是啥样子的

1535879235703

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

脚本如下:

#-*-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()

运行结果

1535879374237

最终答案:CodefestCTF{1_s33_y0u_4r3_a_m4n_0f_sp33d}

 

Web 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 go to next page, that is: you can’t go 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

1535877269304

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

#-*-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

运行下

1535877528777

 

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 go 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()

运行结果如下

1535892298309

最终答案: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,尝试改文件头,发现无效

1535879938784

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

修复完成后,打开即有flag

1535880232974

最终答案: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

1535769690535

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

1535769505500

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

1535882244230

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

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

1535882176697

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

1535882473635

file下,发现是个MP3

1535882547718

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

1535882938272

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

 

Thunder

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

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

1535773565813

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

type flag*.jpg>>all.jpg

以下是all.jpg

1535880779671

得到最终答案: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代码:

1535893121359

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

1535893522278

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

1535894260379

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

1535894689021

最终答案: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解码下

1535897369171

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

1535895884842

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

1535895863184

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

1535896502425

其中的image1.png的尾部存在私钥1535896553352

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

1535897514713

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

1535897143197

最终答案:CodefestCTF{kristeinStewart_is_5EXY}

(完)