前言

期待已久的hgame_week1终于开始了!刚开始的Web马上就ak了,后面几天都在做CryptoMisc,差不多是一天一道的节奏,不得不说,密码学和杂项实在是太难了!!!我脑子都炸了,刚刚 ak 了Misc,现在还差一题才能把Cryptoak。

Web

第一周的web还是蛮有意思的。本来Code Worldcxk的两题卡了蛮久,做出来才发现原来这两题是最简单的…啊还是我太菜了。

Cosmos 的博客

打开题目看到

我们可以看到这里有加粗的版本管理工具GitHub,于是马上想到了.git版本泄露,于是访问/.git。但是却返回404 Not Found,眼看着一血马上从眼前溜走,我赶紧扫一下站

看到这里有一个目录/.git/config,这应该就是git信息储存的目录,访问它我们就应该能获得项目在Github上的地址。

然后访问项目地址,进入了GitHub,想着在commits历史里也许会有flag,点进去看有三个历史记录

一个一个翻看,找到了flag

放到在线base64解密网站,就能拿到flag啦!

还好我手快,最后拿到了第三血!白嫖了 0.5 分,开心,这是hgame的第一题,是个好兆头!

hgame{g1tle@k_1s_danger0us!!!!}

接 头 霸 王

首先访问

既然是come form,又是接头霸王,那么很明显就是要改请求头然后发包了。首先推荐Chrome插件Restlet Client

  • 首先改Refererhttps://vidar.club/
  • 然后要我visit it locally,于是改X-Forwarded-For127.0.0.1
  • 接着要用Cosmos Brower,于是改User_AgentCosmosBrower
  • 完成了之后要我改请求方式为POST,发完之后就是这题最折磨我的地方了!
  • 他说:The flag will be updated after 2077, please wait for it patiently.

在这里我纠结了好久好久,先改Date2077以后的一个时间,没用,然后改电脑本地时间,也不行,尝试了好久,在第二天早上猛然醒悟,再认真地看了看返回头,发现有一个新东西Last_Modified: Fri, 01 Jan 2077 00:00:00 GMT,尝试了发送If-Modified-Since,又失败,抱着试一试的心态,发送了If-Unmodified-Since,居然成功了!!!终于拿到了flag

hgame{W0w!Yourheads@re_s0_many!}

做完题目后去找了 🍆,问完才知道为什么If-Modified-Since不能拿到flag,原来这是一个逻辑问题,我们发包的时间是现在,这时候flag还没有被上传,如果用If-Unmodified-Since应该就可以绕过这个逻辑问题了。

Code World

首先访问

直接就403 Not Forbidden,然后我们打开F12看一下Console

我们看到这里有一个302跳转,于是想到了抓包

这里又是405 Not Allowed,又是nginx,我在这里用了各种单词的组合方式Google,都搜不到我想要的东西,偶然间搜到这一篇,它提到如果把请求方式改一改也许会遇到不一样的情况,于是我改GETPOST,总算不是405了!

于是就是愉快的提交参数啦!先来一个/?a=1+9

提示我再想想?那么我把+urlencode提交再试一试吧。访问/?a=1%2b9

成功拿到flag

hgame{C0d3_1s_s0_S@_sO_C0ol!}

🐔 尼泰玫

这个小游戏贼好玩,我先用普通模式玩通关了才开始做题 23333。首先可以看出的是,这个游戏是靠Javascript运行的。通关条件是分数达到30000分

所以我们找到网站的源文件Sources,找到里面的的JS文件,看到一个skills.js,这应该就是技能文件了,在里面发现了一个隐藏的技能Q技能

class SkillQ extends Skill{constructor(main){super(main,'意念控球','','cxk使用意念控制球转向一次,直接命中最近的一个砖块',10,1000,'Q');}

我悄悄地把技能CD积分消耗都改成0

super(
  main,
  "意念控球",
  "",
  "cxk使用意念控制球转向一次,直接命中最近的一个砖块",
  0,
  0,
  "Q"
);

然后愉快的玩起了游戏…然后我遗憾地发现,我通关了还是只有10000+分,直接哭了,看来还是要找其他的捷径。我们接着看其他的JS文件,找到一个game.js,在第一行我发现一个有关分数的定义

class Game{storageScore=0;globalScore=0;

于是我悄悄地把globalScore改成30001,然后把球一掉,就能取得 flag 了!

hgame{j4vASc1pt_w1ll_tel1_y0u_someth1n9_u5efu1?!}

Pwn

提前预习了一下pwn,签到题还是能做一做的。

Hard_AAAAA

首先把程序扔进ida

看到这里有一个gets()函数,于是想到应该会有栈溢出。接着分析,这里还有一个if条件判断函数,把v5上的值通过memcmp()函数与字符串0O0o进行比较,注意是字符串!顺便看一下sv5的地址。s的地址是0xACv5的地址是0x31,他们是连在一起的。那么我们的目的就很明确了,就是通过gets()函数,把0xAc0x31这段内存覆盖,然后赋值给v5

这里有一个坑,很不幸我踩了,幸亏得到了Cosmos学长的提醒。我们重新分析一下memcmp()函数,读取的是7个字符,比较的确是4个字符?于是我们看一下字符串0O0o所在的内存。

所以其实比较的是'0O0o'+'\0'+'O0'7个字符,而因为\0在字符串里又有截断符的意思,所以我们需要另外传入。于是Payload如下

运行脚本连上远程服务器

hgame{0OoO0oo0O0Oo}

One_Shot

通过这道题,我学会了基本的动态调试…好棒!夸夸自己

首先把程序抛进ida

我们首先看第二个scanf()函数,这个v4是一个指针,我们可以输入任何值以更改指针指向的位置,然后下一行*v4=1会令这个位置的值变为1。那么这里又有什么玄机呢?我们继续看看name所在的位置。

可以看到nameflag在内存上是连在一起的,那么问题就好解决了。在scanf()name进行输入时,函数会自动在字符串末尾加一个\x00作为截断符。而我们可以通过指针的任意位置写入,把字符串的末尾改为任意一个字符,就可以在最后输出的时候把flag一起输出。

脚本如下

Crypto

InfantRSA

首先Google一下了解了RSA是什么东西,然后直接去Github上找到了脚本合集,这里放出Github链接,于是找到对应的脚本,把p,q,C对应的填进去,跑一跑就出flag了。脚本如下:

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


def fastExpMod(b, e, m):
    result = 1
    while e != 0:
        if (e & 1) == 1:
            result = (result * b) % m
        e >>= 1
        b = (b*b) % m
    return result

def computeD(fn, e):
    (x, y, r) = extendedGCD(fn, e)
    if y < 0:
        return fn + y
    return y


def extendedGCD(a, b):
    if b == 0:
        return (1, 0, a)
    x1 = 1
    y1 = 0
    x2 = 0
    y2 = 1
    while b != 0:
        q = a / b
        r = a % b
        a = b
        b = r
        x = x1 - q*x2
        x1 = x2
        x2 = x
        y = y1 - q*y2
        y1 = y2
        y2 = y
    return(x1, y1, a)


def decryption(C, d, n):
    return fastExpMod(C, d, n)


p = 681782737450022065655472455411
q = 675274897132088253519831953441
n = p * q
fn = (p - 1) * (q - 1)
e = 13
d = computeD(fn, e)
C = 275698465082361070145173688411496311542172902608559859019841
M = decryption(C, d, n)
flag = str(hex(M))[2:-1]
print(d)
print(flag.decode('hex'))

flag就出来了

hgame{t3Xt6O0k_R5A!!!}

Affine

这题的解题关键在两点:

  • 我们已经知道了hgame{}A8I5z{}的对应关系
  • MODiii都是已知的或可求的,以此我们可以列出方程组解出AB

两个未知量两个方程就可以求解,于是我们找到前两组字母的对应关系

# 第一组i=12,ii=46,MOD=62
# 第二组i=6,ii=33,MOD=62

于是列出方程组

(12*A+B)%62=46
(6*A+B)%62=33

加加减减可以得出

A%62=13
B%62=14

AB代回

ii=(A*i+B)%MOD

化简得

(13*i%62)=ii-14

于是就得到了形如ax=b(mod n)的模线性方程,从网上拉了一个脚本下来,自己改改,最后得到

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# 求解最大公约数
def ext_euclid(a, b):
    old_s, s = 1, 0
    old_t, t = 0, 1
    old_r, r = a, b
    if b == 0:
        return (1, a)
    else:
        while(r != 0):
            q = old_r//r
            old_r, r = r, old_r-q*r
            old_s, s = s, old_s-q*s
            old_t, t = t, old_t-q*t
    return (old_s, old_r)


flag = ''
TABLE = 'zxcvbnmasdfghjklqwertyuiop1234567890QWERTYUIOPASDFGHJKLZXCVBNM'
MOD = len(TABLE)
secret = "A8I5z{xr1A_J7ha_vG_TpH410}"

for b in secret:
    ii = TABLE.find(b)
    if ii == -1:
        flag += b
    else:
        a = 13
        n = 62
        b = ii - 14
        (i, d) = ext_euclid(a, n)
        i = (i * (b / d)) % n        #求模线性方程的一个特解
        for j in range(d):
            while i < 0:
                i = i + j * (b / d)
            if i > 0:
                break
        flag += TABLE[i]
print(flag)

跑一跑就得到flag

hgame{M4th_u5Ed_iN_cRYpt0}

Reorder

连上远端服务器,随意输入字符串,都会返回一段被重新排序的字符串,在出题人的提示下,我不断尝试,终于找到了这个排序的一点小规律,即每一次连接所用的排序方法都是不同的。但每一种排序方法都有一个共同点:排序时以8个字符为单位,对每一个单位分别排序后输出结果。

最关键的是!!!在每次连接结束时,都会打印一行乱七八糟的字符,但仔细观察可以发现,这一串字符串确实是flag被打乱后的样子!!!那么解题思路就明确了,首先我们要确定某一次的排序方法,然后获得这一次被打乱后的flag,跑一跑脚本就能得出flag了。

为了方便找到排序方法,我们输入一串有规律的字符串,看看输出。第二次输入是为了验证每8个字符为一个单位,可以看出这16个字符中,前8个和后8个的顺序是一模一样的。

于是用肉眼观察法,找到字母的对应顺序,写出排序脚本。

#!usr/bin/env python

b = list('+IUm5mptgheLb{$j')
a = list('xxxxxxxxxxxxxxxx')
d = list('inTe0!!T_3R}PmAu')
c = list('xxxxxxxxxxxxxxxx')

def reorder(a, b):
    a[10] = b[0]  # k
    a[12] = b[1]  # m
    a[7] = b[2]  # h
    a[3] = b[3]  # d
    a[11] = b[4]  # l
    a[13] = b[5]  # n
    a[14] = b[6]  # o
    a[9] = b[7]  # j
    a[1] = b[8]  # b
    a[0] = b[9]  # a
    a[4] = b[10]  # e
    a[15] = b[11]  # p
    a[2] = b[12]  # c
    a[5] = b[13]  # f
    a[8] = b[14]  # i
    a[6] = b[15]  # g



def output(a):
    for i in range(len(a)):
        print(a[i], end='')
reorder(a,b)
output(a)
reorder(c,d)
output(c)

拿到flag

这里有个小小的坑!注意字符串开头应该是hgame,而这里是hgbme,还好我留了个心眼,不然还以为拿到了错的flag

hgame{jU$t+5ImpL3_PeRmuTATi0n!!}

Misc

欢迎参加 HGame!

我们把那一串字符串放到百度里搜,搜到了一个贴吧问题,里面的大致内容是用base64解码,那么问题就明确了,我们把这一串字符串放到在线base64解码工具里,得到了一串摩斯电码

.-- ...-- .-.. -.-. ----- -- . ..--.- - --- ..--.- ..--- ----- ..--- ----- ..--.- .... --. .- -- ...--

再找一个在线摩斯密码解码

得到w3lc0me to 2020 hgam3,然后处理一下,得到flag

hgame{W3LC0ME_TO_2020_HGAM3}

壁纸

把压缩包下载以后解压,里面有一张图片,用记事本打开,看见文件末尾有一句话

Password is Picture ID,看到密码,想到了压缩包,于是看一看这张图片是否是图种。用binwalk分析一波,果然藏着一个压缩包,然后用foremost分离图片和压缩包。

压缩包被加密了,密码就是图片的ID,,合理猜想应该是Pixiv ID,于是把这张图放进Google识图里,搜到图片之后找到ID,然后把ID作为密码解压压缩包。

pixiv上去搜这张图片,搜到ID76953815Google真好用呀!

解压后拿到一个flag.txt,打开后是一串Unicode编码

因为Unicode编码的格式为\uxxxx,所以我们用00补齐,得到

\u0068\u0067\u0061\u006d\u0065\u007b\u0044\u006f\u005f\u0079\u0030\u0075\u005f\u004b\u006e\u004f\u0057\u005f\u0075\u004e\u0069\u0043\u0030\u0064\u0033\u003f\u007d

然后放到在线工具上解码

hgame{Do_y0u_KnOW_uNiC0d3?}

克苏鲁神话

这道题是我最后做出来的Misc,之前有各种愚蠢的想法,好在有了ObjectNotFound学长的帮助,总算是把这道题做出来了。

解压出来后有一个.txt.zip,压缩包有密码,且密码无法解出,但观察可以发现,压缩包里的一个Bacon.txt已经给我们了,于是可以想到用明文攻击破解压缩包密码,所以我把Bacon.txt改为Bacon.zip,然后上工具AAPR

它会将破解后的压缩包保存在另外一个文件夹中,这样我们就可以看到机密压缩包里的内容了。然后打开压缩包,里面一个.txt,一个.doc.doc文档还需要密码,这时候我们就可以去看看.txt里有什么东西。

看到这里,其实题目的提示已经很明显了,又是Bacon,又是大小写混搭的,其实这里是一个培根密码,于是上网找了Python解密脚本,把两种加密方式都试一下,跑一跑就出来密码了。

密码:FLAGHIDDENINDOC,去打开.doc文件,里面没有flag,网上搜一搜.doc文件通常隐写,于是打开隐藏文字flag就出来了。

附上解密脚本

# coding:utf8

import re

alphabet = ['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']

first_cipher = ["aaaaa", "aaaab", "aaaba", "aaabb", "aabaa", "aabab", "aabba",                     "aabbb", "abaaa", "abaab", "ababa", "ababb","abbaa", "abbab",                     "abbba", "abbbb", "baaaa", "baaab", "baaba", "baabb", "babaa",                     "babab", "babba", "babbb", "bbaaa", "bbaab"]

second_cipher = ["AAAAA", "AAAAB", "AAABA", "AAABB", "AABAA", "AABAB", "AABBA",
                 "AABBB", "ABAAA", "ABAAA", "ABAAB", "ABABA", "ABABB", "ABBAA",
                 "ABBAB", "ABBBA", "ABBBB", "BAAAA", "BAAAB", "BAABA",
                 "BAABB", "BAABB", "BABAA", "BABAB", "BABBA", "BABBB",]


def encode():
    upper_flag = False  # 用于判断输入是否为大写
    string = raw_input("please input string to encode:\n")
    if string.isupper():
        upper_flag = True
        string = string.lower()
    e_string1 = ""
    e_string2 = ""
    for index in string:
        for i in range(0, 26):
            if index == alphabet[i]:
                e_string1 += first_cipher[i]
                e_string2 += second_cipher[i]
                break
    if upper_flag:
        e_string1 = e_string1.upper()
        e_string2 = e_string2.upper()
    print "first encode method result is:\n"+e_string1
    print "second encode method result is:\n"+e_string2
    return


def decode():
    upper_flag = False  # 用于判断输入是否为大写
    e_string = raw_input("please input string to decode:\n")
    if e_string.isupper():
        upper_flag = True
        e_string = e_string.lower()
    e_array = re.findall(".{5}", e_string)
    d_string1 = ""
    d_string2 = ""
    for index in e_array:
        for i in range(0, 26):
            if index == first_cipher[i]:
                d_string1 += alphabet[i]
            if index == second_cipher[i]:
                d_string2 += alphabet[i]
    if upper_flag:
        d_string1 = d_string1.upper()
        d_string2 = d_string2.upper()
    print "first decode method result is:\n"+d_string1
    print "second decode method result is:\n"+d_string2
    return


if __name__ == '__main__':
    print "\t\tcoding by qux"
    while True:
        print "\t*******Bacon Encode_Decode System*******"
        print "input should be only lowercase or uppercase,cipher just include a,b(or A,B)"
        print "1.encode\n2.decode\n3.exit"
        s_number = raw_input("please input number to choose\n")
        if s_number == "1":
            encode()
            raw_input()
        elif s_number == "2":
            decode()
            raw_input()
        elif s_number == "3":
            break
        else:
            continue

签到题 ProPlus

解压压缩包,打开,发现里面有一个加密压缩包,和一个Password.txt,打开看一看

于是想到栅栏密码间隔为3凯撒密码间隔为5,先解密英文语句应该是为了判断间隔是否正确。放在线工具上解密,英文语句是Many years later as he faced the firing squad, Colonel Aureliano Buendia was to remember that distant afternoon when his father took him to discover ice.,一看是百年孤独的最著名的一句话,那么说明间隔没问题,于是依葫芦画瓢解密码。

解出来密码是EAVMUBAQHQMVEPDT,拿过去解压压缩包。得到一个OK.txt,里面全是OoK?

Google搜一搜是一种密码,于是找到在线解密工具,解出来是base32

继续解密,解出来一串base64,继续解密,出来一个png

原本我是把base64解密成16进制,然后把16进制数赋复制到010Editor里,这样就出来了一个二维码。其实更简单的解法是什么呢?问了学长才知道,base64本身就可以表示图片,只需要在前面加上前缀data:image/png;base64,加上base64码,在浏览器打开,就可以看到图片了。

把图片放在二维码扫描器里,就可以拿到flag了。

每日推荐

解压压缩包后得到.pcapng文件,那应该就是流量分析题了,用WireShark打开。慢慢寻找,时不时地跟踪TCP流或者HTTP流,看到了在数据传输过程中有一个song.zip,于是想办法把它提取出来,上网搜一搜就有了,看这里

提取出来以后得到加密压缩包song.zip,在学长的提醒下,我用记事本打开它,在文件的末尾看到一行字。

密码是六位数字,那我爆破也许也很快,于是上工具!

得到一个.mp3文件,然后用Audacity打开,看一看频谱图flag就出来了。

后记

我想再去把Cryptoak了。