2019杭电hgame 部分wp
Web
- 谁吃了我的flag hint: 据当事人回忆,那个夜晚他正在用vim编写题目页面,似乎没有保存就关机睡觉去了,现在就是后悔,十分的后悔。
根据提示可以知道这和vim的缓存文件有关 vim会在编辑文件的时候生成一个.swp的缓存文件, 用于意外退出时恢复未保存的文件 目的很明确 下载这个文件 url后面加上/.index.html.swp下载.swp 用winhex打开即可找到flag
-
can u find me?
几个web基础知识 f12找到f12.php 需要post密码 可以在头里找到
password: woyaoflag
用Hackbarpost一个password=woyaoflag 把得到的链接下载下来得到flag
Re
- brainfxxker
#include <iostream>
#include <cctype>
// Orz... I haven't learnt C++ before.
// It seems like my brain was fxxked by these codes...
// Notice:
// 1. the answer is your input when nothing strange was printed
// 2. that is, wrong inputs will encounter with the part "[+.]"
// 3. [!!!] REMEMBER TO WRAP YOUR ANSWER WITH "hgame{" AND "}"
// [!!!] BEFORE YOU SUBMITTED IT
// oyiadin, Jan 18, 2019
// enjoy it! ;)
namespace bf {
class Parser {
public:
Parser() = default;
~Parser() = default;
void execute(const std::string &buf);
protected:
uint8_t data[100] = {0};
int ptr = 0;
};
void Parser::execute(const std::string &buf) {
for (auto i = buf.cbegin(); i != buf.cend(); ++i) {
switch (*i) {
case '>':
++ptr;
break;
case '<':
--ptr;
break;
case '+':
++data[ptr];
break;
case '-':
--data[ptr];
break;
case '.':
putchar(data[ptr]);
break;
case ',':
while ((data[ptr] = getchar()) == '\n') ;
break;
case '[':
if (!data[ptr]) {
while (*i++ != ']') continue;
--i;
}
break;
case ']':
if (data[ptr]) {
while (*(i-1) != '[') --i;
--i;
}
break;
default:
break;
}
}
}
}
int main() {
bf::Parser parser;
parser.execute(",>++++++++++[<---------->-]<++[+.],>+++++++++[<--------->-]<-[+.],>+++++++[<------->-]<---[+.],>++++++[<------>-]<+++[+.],>++++++++[<---------->-]<++[+.],>++++++++++[<---------->-]<--[+.],>++++++++++[<-------->-]<-----[+.],>++++++++++[<---------->-]<+[+.],>+++++++++[<-------->-]<---[+.]");
}
有点像一个vm 直接编译可以运行 随便输入一点东西会返回一堆连续的字符 尝试将指令整理一下 可以发现当最后需要操作的字符为0x00时会停止当前打印字符串的循环 尝试让其只循环一次 构造出几个方程 解方程可得flag
,>++++++++++ [<---------->-] <++ [+.] x-10*10+2=0 b
,>+++++++++ [<--------->-] <- [+.] x-9*9-1=0 R
,>+++++++ [<------->-] <--- [+.] x-7*7-3=0 4
,>++++++ [<------>-] <+++ [+.] x-6*6+3=0 !
,>++++++++ [<---------->-] <++ [+.] x-8*10+2=0 N
,>++++++++++ [<---------->-] <-- [+.] x-100-2=0 f
,>++++++++++ [<-------->-] <----- [+.] x-10*8-5=0 U
,>++++++++++ [<---------->-] <+ [+.] x-100+1=0 c
,>+++++++++ [<-------->-] <--- [+.] x-9*8-3=0 K
- わかります
程序把输入分成了高低位两个数组 都是6 * 6的矩阵 低位和一个已知矩阵进行加运算 高位进行乘运算 最后进行明文对比 低位减回去 高位求个逆乘回去 然后重新组合一下即可求出flag
- ShinyShot!
//ida里看到两个tls, 应该是反调试的, 但是似乎没起作用…
程序最后要满足一个strcmp
其中一个字符串来自程序最后0x20个字节
程序一共有两个输入 第一个是int 被传入了sub_401460
里面有两个 VirtualProtect
发现并不是SMC, 只是中间异或了401000某偏移的某一值
再往下程序fgets了一个长度为22的字符串 然后丢到sub_4014fa
里
进入sub_4014fa
看起来像一个base64编码的过程
shift+F12查找到加密表, 显然不是标准的base64
sub_4014fa
最后将编码出来的字符串前后异或了一下
这里似乎编码后的字符串没有用到, 开始动态分析
这里运行程序程序随便输入一个(无符号整)数(不大于131072) 和一个长22到字符串, 发现程序会崩溃
动态分析看看程序崩溃在了哪里 od依靠字符串定位到main函数 第一次同样随便输入一个数 往下步过到0x4018de的地方发现一个无条件跳转, 直接跳到了0x4018f5的call sub_4014fa //进入了base编码的函数 显然函数没有传参因此导致了崩溃 我们重新设置一下EIP, 程序成功得到了编码后的字符串, 并与程序二进制文件最后0x20个字符进行strcmp
这里先将已知的字符串xor回来
for ( int i = 32; i>0; --i )
{
s[i] ^= s[i-1];
}
再对换表base解码//工具: RandomBase64 可以自定义密码表 得到flag前半部分 输入的整数要把0x4018df处的0x15修改成0x05 整数»3后是偏移0x8df, 1 « (整数 & 7)是拿来和0x15异或的 所以得到整数是(0x8df«3) + 4 //0x15^0x5== 0x10 ==1«4 得到整数0x46fc == 18172
- brainfxxker’s revenge
又是一个brainfxxk
足足上千个符号, 显然不可能一个个看懂的//当然也不可能个个都有意义
稍微读几个, 发现>和<, +和- 是互逆的操作, 所以删掉所有的<>
><
+-
-+
这几个组合, 基本上化简了很多
运行程序发现程序需要输入很多的字符, 然后会有提示信息"wrong answer!" or “congratulations!”
在switch下个断点, 发现程序没有执行case '.': putchar(*ptr);
这一句, 说明还有花代码
但是程序获取输入可以确定是 ’ , ’ 号, 但是一搜索发现足足有上千个//显然不会每个都执行
再观察最后输出反馈信息的语句, 发现判断了data一个标识位是否有值
在最后的default: putchar(*i);
下个断点, 观察data数组
可以看见判断了data[0] 如果有值就输出"wrong answer!", 并且data[0]的值可能会随不同的输入变大或变小//能猜到如果输入正确则data[0]不加1///构造hgame开头的字符串可以验证
下断点稍微跟程序跑一下, 发现每一次输入主要依靠,>++…
在前面加个换行整理一下, 一共72行//正好就是data[0]的最大值, 也是输入的字符串长度
//其中[-]
这个结构是用来归零循环标志位的
把没有进入的循环删除掉
再稍微整理一下得到
>
,>++++++++ [<------------->-]<//h
,>++++++++ [<------------>-]<-------//g
,>++++++++ [<------------>-]<-//a
,>++++++ [<------------------>-]<-//m
,>++++++ [<---------------->-]<-----//e
,>++++++++ [<--------------->-]<---//{
,>++++++++++ [<---------->-]//d
,>++++++++++ [<---------->-]<--//f
,>++++++++++ [<----->-]<---//5
,>+++++++ [<-------->-]<-//9
,>++++++ [<----------------->-]<//f
,>+++++++ [<------->-]<------//7
,>+++++++ [<-------------->-]<//b
,>+++++ [<------------------->-]<--//a
,>++++++++++ [<---------->-]<//d
,>++++++ [<-------->-]<---//3
......
得到flag
misc
- Try
得到一个数据包 筛选出http 找到包含zip的包, 选定media type的位置, 点击file->export selected Packet Bytes, 在弹出的框中将文件保存成二进制文件
一个password.txt和一个带密码的压缩包 掩码爆破hgame????????得到压缩包密码 解压出一张图片 binwalk可以发现有个压缩包 提取出来是伪加密 改一下标识位 得到.docx 把docx解压找到word文件夹 有个文件里有flag
Crypto
- perfect_secrecy!
一个py脚本 flag和 poem.txt 未知 提示OTP(一次性密码) 题中多次用一个随机密码按位异或明文 因此密文相互异或就可以干掉一次性密码 然后分析出明文 git上找到脚本
#!/usr/bin/python
## OTP - Recovering the private key from a set of messages that were encrypted w/ the same private key (Many time pad attack) - crypto100-many_time_secret @ alexctf 2017
# Original code by jwomers: https://github.com/Jwomers/many-time-pad-attack/blob/master/attack.py)
import string
import collections
import sets, sys
# 11 unknown ciphertexts (in hex format), all encrpyted with the same key
c1='daaa4b4e8c996dc786889cd63bc4df4d1e7dc6f3f0b7a0b61ad48811f6f7c9bfabd7083c53ba54'
c2='c5a342468c8c7a88999a9dd623c0cc4b0f7c829acaf8f3ac13c78300b3b1c7a3ef8e193840bb'
c3='dda342458c897a8285df879e3285ce511e7c8d9afff9b7ff15de8a16b394c7bdab920e7946a05e9941d8308e'
c4='d9b05b4cd5ce7c8f938bd39e24d0df191d7694dfeaf8bfbb56e28900e1b8dff1bb985c2d5aa154'
c5='d9aa4b00c88b7fc79d99d38223c08d54146b88d3f0f0f38c03df8d52f0bfc1bda3d7133712a55e9948c32c8a'
c6='c4b60e46c9827cc79e9698936bd1c55c5b6e87c8f0febdb856fe8052e4bfc9a5efbe5c3f57ad4b9944de34'
c7='d9aa5700da817f94d29e81936bc4c1555b7b94d5f5f2bdff37df8252ffbecfb9bbd7152a12bc4fc00ad7229090'
c8='c4e24645cd9c28939a86d3982ac8c819086989d1fbf9f39e18d5c601fbb6dab4ef9e12795bbc549959d9229090'
c9='d9aa4b598c80698a97df879e2ec08d5b1e7f89c8fbb7beba56f0c619fdb2c4bdef8313795fa149dc0ad4228f'
c10='cce25d48d98a6c8280df909926c0de19143983c8befab6ff21d99f52e4b2daa5ef83143647e854d60ad5269c87'
c11='d9aa4b598c85668885df9d993f85e419107783cdbee3bbba1391b11afcf7c3bfaa805c2d5aad42995ede2cdd82977244'
ciphers = [c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11]
# The target ciphertext we want to crack
# XORs two string
def strxor(a, b): # xor two strings (trims the longer input)
return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b)])
def target_fix(target_cipher):
print '-------begin-------'
# To store the final key
final_key = [None]*150
# To store the positions we know are broken
known_key_positions = set()
# For each ciphertext
for current_index, ciphertext in enumerate(ciphers):
counter = collections.Counter()
# for each other ciphertext
for index, ciphertext2 in enumerate(ciphers):
if current_index != index: # don't xor a ciphertext with itself
for indexOfChar, char in enumerate(strxor(ciphertext.decode('hex'), ciphertext2.decode('hex'))): # Xor the two ciphertexts
# If a character in the xored result is a alphanumeric character, it means there was probably a space character in one of the plaintexts (we don't know which one)
if char in string.printable and char.isalpha(): counter[indexOfChar] += 1 # Increment the counter at this index
knownSpaceIndexes = []
# Loop through all positions where a space character was possible in the current_index cipher
for ind, val in counter.items():
# If a space was found at least 7 times at this index out of the 9 possible XORS, then the space character was likely from the current_index cipher!
if val >= 7: knownSpaceIndexes.append(ind)
#print knownSpaceIndexes # Shows all the positions where we now know the key!
# Now Xor the current_index with spaces, and at the knownSpaceIndexes positions we get the key back!
xor_with_spaces = strxor(ciphertext.decode('hex'),' '*150)
for index in knownSpaceIndexes:
# Store the key's value at the correct position
final_key[index] = xor_with_spaces[index].encode('hex')
# Record that we known the key at this position
known_key_positions.add(index)
# Construct a hex key from the currently known key, adding in '00' hex chars where we do not know (to make a complete hex string)
final_key_hex = ''.join([val if val is not None else '00' for val in final_key])
# Xor the currently known key with the target cipher
output = strxor(target_cipher.decode('hex'),final_key_hex.decode('hex'))
print "Fix this sentence:"
print ''.join([char if index in known_key_positions else '*' for index, char in enumerate(output)])+"\n"
# WAIT.. MANUAL STEP HERE
# This output are printing a * if that character is not known yet
# fix the missing characters like this: "Let*M**k*ow if *o{*a" = "cure, Let Me know if you a"
# if is too hard, change the target_cipher to another one and try again
# and we have our key to fix the entire text!
#sys.exit(0) #comment and continue if u got a good key
print '------end------'
for i in ciphers:
target_fix(i)
这里只选用了11行密文进行修复 可以发现其中
-------begin-------
Fix this sentence:
*hen*we two parted In silence *n* tear*
------end------
能基本识别出正常含义 谷歌这句话 发现是一首由乔治·戈登·拜伦创作的诗歌《When We Two Parted》中的第一句话
When we two parted in silence and tears
那么一条明文出来了 把这句话和第一条密文按位异或 就可以推出随机的密钥了
最后拿密钥按位异或被加密的flag 得到flag