0x0 背景

弃坑Arcaea一年多了,周六还是偶然打开某arc群时还是发现几个大佬在发 Hackergame 2021排名截图。真巧,今年也来玩一玩。不过现在变身成为打工人后空闲时间只顾着咸鱼了,花了一上午挑了一些简单的题目做完后直接摆烂了......

0x1 题目

签到

众所周知本题应该不难,上来是需要在限定时间内手写2022并通过识别后提交。打开HTML源码看到是Vue写的,第一时间就是修改时间限制。但往下翻翻发现提交函数直接拼接了识别结果。果然还是想难了.....随便提交一个结果后将传参改为?result=2022即可。

flag{HappyHacking2022-1a3d895fa6}

猫咪问答 Pro Max

参考历年题目,考察信息搜索能力。

中国科学技术大学 NEBULA 战队(USTC NEBULA)是于何时成立的喵?

直接Google搜索USTC NEBULA成立时间得知为2017-03

2022 年 9 月,中国科学技术大学学生 Linux 用户协会(LUG @ USTC)在科大校内承办了软件自由日活动。除了专注于自由撸猫的主会场之外,还有一些和技术相关的分会场(如闪电演讲 Lightning Talk)。其中在第一个闪电演讲主题里,主讲人于 slides 中展示了一张在 GNOME Wayland 下使用 Wayland 后端会出现显示问题的 KDE 程序截图,请问这个 KDE 程序的名字是什么?

Google LUG @ USTC GNOME Wayland 可找到并下载Slides,截图在第15页,注意一条菜单项叫Configure Kdenlive,那程序名就很明显了。

22 年坚持,小 C 仍然使用着一台他从小用到大的 Windows 2000 计算机。那么,在不变更系统配置和程序代码的前提下,Firefox 浏览器能在 Windows 2000 下运行的最后一个大版本号是多少?

Google Windows 2000可得12

你知道 PwnKit(CVE-2021-4034)喵?据可靠谣传,出题组的某位同学本来想出这样一道类似的题,但是发现 Linux 内核更新之后居然不再允许 argc 为 0 了喵!那么,请找出在 Linux 内核 master 分支(torvalds/linux.git)下,首个变动此行为的 commit 的 hash 吧喵!

找到此仓库torvalds/linux: Linux kernel source tree (github.com)并搜索CVE-2021-4034可得dcd46d897adb70d63e025f175a00a89797d31a43

通过监视猫咪在键盘上看似乱踩的故意行为,不出所料发现其秘密连上了一个 ssh 服务器,终端显示 ED25519 key fingerprint is MD5:e4:ff:65:d7:be:5d:c8:44:1d:89:6b:50:f5:50:a0:ce.,你知道猫咪在连接什么域名吗?

直接GoogleMD5:e4:ff:65:d7:be:5d:c8:44:1d:89:6b:50:f5:50:a0:ce可以在第二页找到ssh.log — Book of Zeek (git/master)此页面。在#outbound-movement中可发现连接的IP地址为205.166.94.16。直接访问看邮箱域名可得sdf.org

中国科学技术大学可以出校访问国内国际网络从而允许云撸猫的“网络通”定价为 20 元一个月是从哪一天正式实行的?

Google中国科学技术大学 网络通 20元可以找到关于实行新的网络费用分担办法的通知-中国科学技术大学 (ustc.edu.cn)此页面。得知旧的费用分担办法已经为20元一个月。使用关键词网络费用分担办法的通知 2003年在Google没搜到结果,百度居然给了结果关于实行新的网络费用分担办法的通知 (ustc.edu.cn)。由文件可知2003-03-01

flag1:flag{meowexammeow_772b498346fe0925_1e02f422c8}

flag2:flag{meowexamfullymeowed!_6c159adddb7f171b_8f2fb889d9}

家目录里的秘密

用过rclone,知道配置文件默认在.config下,翻了下发现Code也在这个目录,一顿翻找找到user\.config\Code\User\History\2f23f721\DUGV.c文件。这才知道原来VSCode有保存历史文件。然后想到直接全文检索flag其实更容易定位到......

说回rclone,此前尝试写世纪互联版OneDrive的实现时有研究过rclone。知道rclone将明文密码”加密“后保存。这次打开配置文件后可以看出ftp的各种配置都没啥用,只有pass字段值的钻研下。rclone加密的方式在rclone/obscure.go at master · rclone/rclone (github.com)。最优解是调用此func Reveal(x string):

package main

import (
    "crypto/aes"
    "crypto/cipher"
    "crypto/rand"
    "encoding/base64"
    "errors"
    "fmt"
)

// crypt internals
var (
    cryptKey = []byte{
        0x9c, 0x93, 0x5b, 0x48, 0x73, 0x0a, 0x55, 0x4d,
        0x6b, 0xfd, 0x7c, 0x63, 0xc8, 0x86, 0xa9, 0x2b,
        0xd3, 0x90, 0x19, 0x8e, 0xb8, 0x12, 0x8a, 0xfb,
        0xf4, 0xde, 0x16, 0x2b, 0x8b, 0x95, 0xf6, 0x38,
    }
    cryptBlock cipher.Block
    cryptRand  = rand.Reader
)

// crypt transforms in to out using iv under AES-CTR.
//
// in and out may be the same buffer.
//
// Note encryption and decryption are the same operation
func crypt(out, in, iv []byte) error {
    if cryptBlock == nil {
        var err error
        cryptBlock, err = aes.NewCipher(cryptKey)
        if err != nil {
            return err
        }
    }
    stream := cipher.NewCTR(cryptBlock, iv)
    stream.XORKeyStream(out, in)
    return nil
}

// Reveal an obscured value
func Reveal(x string) (string, error) {
    ciphertext, err := base64.RawURLEncoding.DecodeString(x)
    if err != nil {
        return "", fmt.Errorf("base64 decode failed when revealing password - is it obscured?: %w", err)
    }
    if len(ciphertext) < aes.BlockSize {
        return "", errors.New("input too short when revealing password - is it obscured?")
    }
    buf := ciphertext[aes.BlockSize:]
    iv := ciphertext[:aes.BlockSize]
    if err := crypt(buf, buf, iv); err != nil {
        return "", fmt.Errorf("decrypt failed when revealing password - is it obscured?: %w", err)
    }
    return string(buf), nil
}

func main() {
    out, _ := Reveal("tqqTq4tmQRDZ0sT_leJr7-WtCiHVXSMrVN49dWELPH1uce-5DPiuDtjBUN3EI38zvewgN5JaZqAirNnLlsQ")
    fmt.Println(out)
}

跑一下就得到了结果。

result

整活解法:

  • pip3 install pyftpdlib
  • 修改site-packages
  • 开启服务器python -m pyftpdlib -D
  • 成功打印出密码

    lol

VSCode:flag{finding_everything_through_vscode_config_file_932rjdakd}

Rclone: flag{get_rclone_password_from_config!_2oi3dz1}

HeiLang

来自 Heicore 社区的新一代编程语言 HeiLang,基于第三代大蟒蛇语言,但是抛弃了原有的难以理解的 | 运算,升级为了更加先进的语法,用 A[x | y | z] = t 来表示之前复杂的 A[x] = t; A[y] = t; A[z] = t

作为一个编程爱好者,我觉得实在是太酷了,很符合我对未来编程语言的想象,科技并带着趣味。

这里描述很乐,根据描述的语法来修复代码即可。

with open('getflag.hei.py', 'r') as f:
    lines = f.readlines()
    for i in range(0, len(lines)):
        if lines[i].startswith('a['):
            indexs = lines[i].split('[')[1].split(']')[0].split('|')
            result = lines[i].split('=')[1].strip() 
            lines[i] = ''
            for index in indexs:
                index = index.strip()
                lines[i] += f'a[{index}] = {result};'

with open('getflag.hei.fixed.py', 'w') as f:
    f.writelines(lines)

最后一下修复后的代码得到flag

flag{6d9ad6e9a6268d96-cb74a571dc764044}

Xcaptcha

拿到这题后发现是延时1秒自动提交结果,首先的想法是抓包再手动提交。抓包后用Python逐个计算了下结果提交后发现还是返回验证失败:超过 1 秒限制

搞不清楚后端是如何判断时间是否超时的,第一个怀疑是通过Cookie,奈何技术力低下看不懂如何解Cookie就跳过了,不过看起来Cookie像是JWT Token。接下来尝试了给请求Header加Date,时间改到了2042年,未果。然后就没有头绪了,只能尝试硬解。拿出Tampermonkey写了一段脚本后通过计算:

function cal(captcha){
    let split = captcha.split('+');
    let left = BigInt(split[0]);
    split = split[1].split(' ');
    let right = BigInt(split[0]);
    let result = left + right;
    return result;
}

(function() {
    'use strict';

    let captcha1 = document.querySelector("label[for=captcha1").textContent;
    document.getElementById('captcha1').value=cal(captcha1);

    let captcha2 = document.querySelector("label[for=captcha2").textContent;
    document.getElementById('captcha2').value=cal(captcha2);

    let captcha3 = document.querySelector("label[for=captcha3").textContent;
    document.getElementById('captcha3').value=cal(captcha3);

    document.getElementById('submit').click();
})();

拿到flag后看意思果然应该还是在header里做文章,等题解......

flag{head1E55_br0w5er_and_ReQuEsTs_areallyour_FR1ENd_c6c5697944}

旅行照片 2.0

今年的旅行照片居然没有隐去EXIF,第一题查看EXIF即可得到答案:

flag{1f_y0u_d0NT_w4nt_shOw_theSe_th3n_w1Pe_EXlF}

第二题未解完:
酒店:
  1. 放大图片观察建筑可以看到WELCOME TO ZOZOMA***E STADIUM,谷歌得知地点为日本千叶ZOZO海洋球场。查看对面大概位置酒店的邮编即可2610021
  2. 根据上题EXIF得知手机厂商为小米,CPU为sm6115,即高通骁龙662。那么对应的手机为红米Note 9。分辨率为2340x1080

Geo

航班:
  1. 地图放大后看附近机场,再看飞行方向猜测很大可能是羽田机场起飞。但查航线回放时发现要会员,也懒得遍历就摆烂了......

Flag 自动机

这题用动态调试+patch过了。永远无法触及的狠心夺取按钮直接不管,我们要做的是让放手离开按钮按下后执行打印flag的逻辑。IDA打开后发现无法调试,找了找方法发现sub_4083AC中检测了调试器,直接把call exitnop掉即可。

查看sub_401510伪代码:

LRESULT __stdcall sub_401510(HWND hWndParent, UINT Msg, WPARAM a3, LPARAM lParam)
{
  size_t v4; // eax
  FILE *Stream; // [esp+40h] [ebp-18h]
  void *Block; // [esp+44h] [ebp-14h]
  HFONT wParam; // [esp+48h] [ebp-10h]
  unsigned int dwNewLong; // [esp+4Ch] [ebp-Ch]

  switch ( Msg )
  {
    case 2u:
      PostQuitMessage(0);
      break;
    case 0x111u:
      if ( (_WORD)a3 == 2 )
        PostQuitMessage(0);
      if ( (_WORD)a3 == 3 )
      {
        if ( lParam == 114514 )
        {
          Block = (void *)sub_401F8A(hWndParent, 114514);
          MessageBoxW(hWndParent, "m`淯`O穬梍 ", L"Congratulations", 0);
          Stream = fopen("flag_machine.txt", "w");
          if ( !Stream )
          {
            MessageBoxW(hWndParent, "噀鯪Sb", "E", 0);
            free(Block);
            exit(-1);
          }
          v4 = strlen((const char *)Block);
          fwrite(Block, 1u, v4, Stream);
          fclose(Stream);
          free(Block);
        }
        else
        {
          MessageBoxW(hWndParent, "穬諷 ", "E", 0);
        }
      }
      break;
    case 1u:
      hWnd = CreateWindowExW(0, "B", "鄏胈:Y諷", 0x50000000u, 85, 150, 80, 25, hWndParent, (HMENU)3, 0, 0);
      dword_40B024 = CreateWindowExW(0, "B", ">eKb粂", 0x50000000u, 185, 150, 80, 25, hWndParent, (HMENU)2, 0, 0);
      dword_40B028 = CreateWindowExW(
                       0,
                       &word_40A04A,
                       lpWindowName,
                       0x50000000u,
                       85,
                       100,
                       300,
                       20,
                       hWndParent,
                       (HMENU)1,
                       0,
                       0);
      dwNewLong = GetWindowLongA(hWndParent, -16) & 0xFFFEFFFF;
      SetWindowLongA(hWndParent, -16, dwNewLong);
      wParam = CreateFontW(12, 0, 0, 0, 400, 0, 0, 0, 0x86u, 0, 0, 2u, 0x12u, "媅SO");
      SendMessageA(hWndParent, 0x30u, (WPARAM)wParam, 1);
      SendMessageA(hWnd, 0x30u, (WPARAM)wParam, 1);
      SendMessageA(dword_40B024, 0x30u, (WPARAM)wParam, 1);
      SendMessageA(dword_40B028, 0x30u, (WPARAM)wParam, 1);
      break;
  }
  return DefWindowProcW(hWndParent, Msg, a3, lParam);
}

可以发现重要的判断有if ( (_WORD)a3 == 3 )if ( lParam == 114514 ),而动调sub_401510时可发现当按下放手离开按钮,a3 = 2,那么只需patch程序,调换下条件即可。另外需要保证[ebp+lParam]为114514 mov [ebp+lParam], 114514

flag{Y0u_rea1ly_kn0w_Win32API_89ab91ac0c}

Flag 的痕迹

(题目 Dokuwiki 版本基于 2022-07-31a "Igor")

看到题目强调版本,我感觉可能有些问题,故而翻了翻官方的commit历史,然后翻到了这条SECURITY fix difftype handling. #3761SECURITY fix difftype handling. #3761 · splitbrain/dokuwiki@63e9a24 (github.com)

进去看了下,没用到这个XSS,但发现原来?do=diff即便在revisions关掉后也可以查看历史。那往前翻翻到这就发现flag啦/doku.php?id=start&do=diff&rev2[0]=1665224461&rev2[1]=1666320802&difftype=sidebyside

flag{d1gandFInD_d0kuw1k1_unexpectEd_API}

微积分计算小练习

看了看网页源码后可以发现直接将query丢到了innerHTML。摆明了就是要XSS,而”后台“也是拿面页里的数据来用。拿注入一下打印cookie就好了。

100:<img src=x onerror="document.querySelector('#greeting').innerText=document.cookie">

flag{xS5_1OI_is_N0t_SOHARD_d94d8efdc1}

0x2 尾巴

怎么说呢,感觉近期动力不充足。白天工作完了晚上也有项目,一周到了末尾只想咸鱼,逛逛B站、打打游戏,其它什么都不想动。这一年也没什么目标基本没有再钻研过逆向,没有掌握新逆向知识。感觉这个状态不对,但不知道怎么走出来......

最后分数:

请输入图片描述

Questions

最后修改:2022 年 11 月 14 日
如果觉得我的文章对你有用,请随意赞赏