8

Real World CTF 2018 ccls-fringe命题报告

 3 years ago
source link: http://maskray.me/blog/2018-07-31-real-world-ctf-2018-ccls-fringe
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Real World CTF 2018 ccls-fringe命题报告

上周日给Real World CTF 2018出了一道forensics题ccls-fringe,向解出此题的31支队伍表达祝贺。

上一次出题已是2016年,一直没有人教我pwn、reverse、web所以只能从平常接触的东西里勉强抽出要素弄成题目。

kelwya找我来出题,他说forensics也可以,阻止了我说另请高明。另外也想给自己的项目打广告,萌生了从ccls的cache弄一道forensics的想法,因为惰性拖了两个星期没有动手。之前一次LeetCode Weekly前在和一个学弟聊天,就想把他的id嵌入了flag。LeetCode第一题Leaf-Similar Trees没有叫成same-fringe,所以我的题目就带上fringe字样“科普”一下吧。

下载ccls-fringe.tar.xz后解压得到.ccls-cache/@home@flag@/fringe.cc.blob。这是存储的cache文件。

这里体现了ccls和cquery的一个不同点。ccls默认使用"cacheFormat":"binary"了,这个自定义的简单序列化格式,cquery仍在使用JSON。

写段程序读入文件,用ccls::Derialize反序列化成IndexFile,用ToString可以转成JSON字串,阅读可以发现其中一个变量int b

"usr": 7704954053858737267,
"detailed_name": "int b",
"qual_name_offset": 4,
"short_name_offset": 4,
"short_name_size": 1,
"hover": "",
"comments": "flag is here",
"declarations": [],
"spell": "16:80-16:81|1935187987660993811|3|2",
"extent": "16:76-16:81|1935187987660993811|3|0",
"type": 52,
"uses": [],
"kind": 13,
"storage": 0

clang -fparse-all-comments会把非Doxygen注释也嵌入AST,注释暗示了我们应该找和它类似的变量。spell差不多表示spelling SourceRange,第80列很奇怪。写一段程序收集位于80列的其他单字符变量,按行号排序:

#include "indexer.h"
const char blob[] = ".ccls-cache/@home@flag@/fringe.cc.blob";
__attribute__((constructor)) void solve() {
std::string content = *ReadContent(blob);
auto file = ccls::Deserialize(SerializeFormat::Binary, blob, content, "", {});
std::vector<std::pair<int, char>> wod;
for (auto &[usr, v] : file->usr2var) {
Maybe<Use> spell = v.def.spell;
if (spell) {
Position start = spell->range.start;
if (start.column == 79)
wod.emplace_back(start.line, v.def.detailed_name[4]);
sort(wod.begin(), wod.end());
for (auto t: wod)
putchar(t.second);
puts("");
exit(0);

Makefile指定编译选项和链接选项,除了LLVM只有rapidjson一个依赖了。

CCLS := $(HOME)/Dev/Util/ccls
LLVM := $(HOME)/Dev/llvm
LDFLAGS := -shared
CXXFLAGS := -std=c++17 -fPIC -g
CXXFLAGS += -I$(CCLS)/src -I$(CCLS)/third_party -I$(CCLS)/third_party/rapidjson/include
CXXFLAGS += -I$(LLVM)/include -I$(LLVM)/Release/include
CXXFLAGS += -I$(LLVM)/tools/clang/include -I$(LLVM)/Release/tools/clang/include
solve.so: solve.cc
$(LINK.cc) $^ -o $@

编译成ccls.so,让ccls吐出flag:

% LD_PRELOAD=./ccls.so ~/Dev/Util/ccls/Debug/ccls
blesswodwhoisinhk

这只是这人用的id的一个子串,他教育我要多做Codeforces,是很好玩的(可惜我依然这么菜,呜呜😭😭😿😿)。

把same-fringe problem写成coroutine形式也是为了纪念一个去New York City的同学,他在Stanford读研期间,给一门课当助教时曾让我校对一个课程实验Cooperative User-Level Threads。

#include <iostream>
#include <vector>
#include <ucontext.h>
using namespace std;
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
struct Co {
ucontext_t c;
char stack[8192];
TreeNode *ret;
Co(ucontext_t *link, void (*f)(Co *, TreeNode *), TreeNode *root) { {int b; /* flag is here */}
getcontext(&c); {int l;}
c.uc_stack.ss_sp = stack; {int e;}
c.uc_stack.ss_size = sizeof stack; {int s;}
c.uc_link = link; {int s;}
makecontext(&c, (void(*)())f, 2, this, root);
void yield(TreeNode *x) { {int w;}
ret = x; {int o;}
swapcontext(&c, c.uc_link); {int d;}
void dfs(Co *c, TreeNode *x) { {int w;}
if (!x) return; {int h;}
if (!x->left && !x->right) c->yield(x); {int o;}
dfs(c, x->left); {int i;}
dfs(c, x->right); {int s;}
class Solution {
public:
bool leafSimilar(TreeNode *root1, TreeNode *root2) { {int i;}
ucontext_t c; {int n;}
Co c2(&c, dfs, root2), c1(&c2.c, dfs, root1); {int h;}
do { {int k;}
c1.ret = c2.ret = nullptr;
swapcontext(&c, &c1.c);
} while (c1.ret && c2.ret && c1.ret->val == c2.ret->val);
return !c1.ret && !c2.ret;
void insert(TreeNode **x, TreeNode &y) {
while (*x)
x = y.val < (*x)->val ? &(*x)->left : &(*x)->right;
*x = &y;
int main() {
TreeNode xs[] = {{3},{1},{5},{0},{2},{4},{6}};
TreeNode ys[] = {{5},{3},{6},{1},{4},{0},{2}};
TreeNode zs[] = {{3},{1},{5},{0},{2},{6}};
TreeNode *tx = nullptr, *ty = nullptr, *tz = nullptr;
for (auto &x: xs) insert(&tx, x);
for (auto &y: ys) insert(&ty, y);
for (auto &z: zs) insert(&tz, z);
Solution s;
cout << s.leafSimilar(tx, ty) << endl;
cout << s.leafSimilar(tx, tz) << endl;

假如你用clang trunk (>=7),ccls可以检索macro replacement-list中的引用。某些限定条件下template instantiation得到的引用也能索引。

https://github.com/MaskRay/RealWorldCTF-2018-ccls-fringe

ccls的xref功能可以看https://github.com/MaskRay/ccls/wiki/Emacs里的截图。Vim/NeoVim用户也强烈建议看看Emacs能达到什么效果。最近也加了一个vscode-ccls,但我不用VSCode因此没有精力维护。

Teilen Kommentare


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK