2021 L3HCTF luuuua Writeup

AAA:immortal

这题做完以后感觉和ByteCTF2021的language binding很像,这是我之前写的Writeup 。

首先打开java层,发现asserts/res/test.lua里的逻辑是假的。然后通过LoginActivity里的afterTextChanged方法找到关键的b.c.a.b.a.d。 注意它

import org.keplerproject.luajava.LuaState; import org.keplerproject.luajava.LuaStateFactory;

所以在网上找到了对应的github:luajava,和一些使用例子:

public void invokeFileScript(String scriptFilePath){LuaState luaState = LuaStateFactory.newLuaState();luaState.openLibs();this.initLuaContext(luaState);int error = luaState.LdoFile(scriptFilePath);if(error!=0){Logger.log("Read/Parse lua error. Exit");return;}luaState.close();
}

所以我们发现真正的逻辑在logo.jpg上,010editor打开找了一下发现真的有加密了的luac脚本。异或0x3c解密以后得到了luac脚本,unluac尝试反汇编发现报错。和byteCTF那道一样改了opcode的位置,因此需要逆向.so文件找到真正的opcode解析的方法。

with open('logo.jpg','rb') as f:con = f.read()
con = con[0x3afa2:]
with open('dec.luac','wb') as fs:fs.write(b'\x1b')for c in con:fs.write(bytes([0x3c^c]))

使用Android里的ndk工具链重新编译了lua5.3的源码,得到了正确的.so文件。两者对照以后慢慢逆向恢复出正确的opcodes。

然后和ByteCTF一样,魔改一下unluac脚本,反编译出了lua脚本:

local base64 = {}
local extract = _G.bit32 and _G.bit32.extract
if not extract thenif _G.bit thenlocal shl, shr, band = _G.bit.lshift, _G.bit.rshift, _G.bit.bandfunction extract(v, from, width)return band(shr(v, from), shl(1, width) - 1)endelseif _G._VERSION == "Lua 5.1" thenfunction extract(v, from, width)local w = 0local flag = 2 ^ fromfor i = 0, width - 1 dolocal flag2 = flag + flagif flag <= v % flag2 thenw = w + 2 ^ iendflag = flag2endreturn wendelseextract = load([[
return function( v, from, width )return ( v >> from ) & ((1 << width) - 1)end]])()end
end
function base64.makeencoder(s62, s63, spad)local encoder = {}for b64code, char in pairs({[0] = "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","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","0","1","2","3","4","5","6","7","8","9",s62 or "+",s63 or "/",spad or "="}) doencoder[b64code] = char:byte()endreturn encoder
end
function base64.makedecoder(s62, s63, spad)local decoder = {}for b64code, charcode in pairs(base64.makeencoder(s62, s63, spad)) dodecoder[charcode] = b64codeendreturn decoder
end
local DEFAULT_ENCODER = base64.makeencoder()
local DEFAULT_DECODER = base64.makedecoder()
local char, concat = string.char, table.concat
function base64.encode(str, encoder, usecaching)encoder = encoder or DEFAULT_ENCODERlocal t, k, n = {}, 1, #strlocal lastn = n % 3local cache = {}for i = 1, n - lastn, 3 dolocal a, b, c = str:byte(i, i + 2)local v = a * 65536 + b * 256 + clocal sif usecaching thens = cache[v]if not s thens = char(encoder[extract(v, 18, 6)], encoder[extract(v, 12, 6)], encoder[extract(v, 6, 6)], encoder[extract(v, 0, 6)])cache[v] = sendelses = char(encoder[extract(v, 18, 6)], encoder[extract(v, 12, 6)], encoder[extract(v, 6, 6)], encoder[extract(v, 0, 6)])endt[k] = sk = k + 1endif lastn == 2 thenlocal a, b = str:byte(n - 1, n)local v = a * 65536 + b * 256t[k] = char(encoder[extract(v, 18, 6)], encoder[extract(v, 12, 6)], encoder[extract(v, 6, 6)], encoder[64])elseif lastn == 1 thenlocal v = str:byte(n) * 65536t[k] = char(encoder[extract(v, 18, 6)], encoder[extract(v, 12, 6)], encoder[64], encoder[64])endreturn concat(t)
end
function base64.decode(b64, decoder, usecaching)decoder = decoder or DEFAULT_DECODERlocal pattern = "[^%w%+%/%=]"if decoder thenlocal s62, s63for charcode, b64code in pairs(decoder) doif b64code == 62 thens62 = charcodeelseif b64code == 63 thens63 = charcodeendendpattern = ("[^%%w%%%s%%%s%%=]"):format(char(s62), char(s63))endb64 = b64:gsub(pattern, "")local cache = usecaching and {}local t, k = {}, 1local n = #b64local padding = b64:sub(-2) == "==" and 2 or b64:sub(-1) == "=" and 1 or 0for i = 1, padding > 0 and n - 4 or n, 4 dolocal a, b, c, d = b64:byte(i, i + 3)local sif usecaching thenlocal v0 = a * 16777216 + b * 65536 + c * 256 + ds = cache[v0]if not s thenlocal v = decoder[a] * 262144 + decoder[b] * 4096 + decoder[c] * 64 + decoder[d]s = char(extract(v, 16, 8), extract(v, 8, 8), extract(v, 0, 8))cache[v0] = sendelselocal v = decoder[a] * 262144 + decoder[b] * 4096 + decoder[c] * 64 + decoder[d]s = char(extract(v, 16, 8), extract(v, 8, 8), extract(v, 0, 8))endt[k] = sk = k + 1endif padding == 1 thenlocal a, b, c = b64:byte(n - 3, n - 1)local v = decoder[a] * 262144 + decoder[b] * 4096 + decoder[c] * 64t[k] = char(extract(v, 16, 8), extract(v, 8, 8))elseif padding == 2 thenlocal a, b = b64:byte(n - 3, n - 2)local v = decoder[a] * 262144 + decoder[b] * 4096t[k] = char(extract(v, 16, 8))endreturn concat(t)
end
local strf = string.format
local byte, char = string.byte, string.char
local spack, sunpack = string.pack, string.unpack
local app, concat = table.insert, table.concat
local stohex = function(s, ln, sep)if #s == 0 thenreturn ""endif not ln thenreturn (s:gsub(".", function(c)return strf("%02x", byte(c))end))endsep = sep or ""local t = {}for i = 1, #s - 1 dot[#t + 1] = strf("%02x%s", s:byte(i), i % ln == 0 and "\n" or sep)endt[#t + 1] = strf("%02x", s:byte(#s))return concat(t)
end
local hextos = function(hs, unsafe)local tonumber = tonumberif not unsafe thenhs = string.gsub(hs, "%s+", "")if string.find(hs, "[^0-9A-Za-z]") or #hs % 2 ~= 0 thenerror("invalid hex string")endendreturn hs:gsub("(%x%x)", function(c)return char(tonumber(c, 16))end)
end
local stx = stohex
local xts = hextos
local ROUNDS = 64
local keysetup = function(key)assert(#key == 16)local kt = {0,0,0,0}kt[1], kt[2], kt[3], kt[4] = sunpack(">I4I4I4I4", key)local skt0 = {}local skt1 = {}local sum, delta = 0, 2654435769for i = 1, ROUNDS doskt0[i] = sum + kt[(sum & 3) + 1]sum = sum + delta & 4294967295skt1[i] = sum + kt[(sum >> 11 & 3) + 1]endreturn {skt0 = skt0, skt1 = skt1}
end
local encrypt_u64 = function(st, bu)local skt0, skt1 = st.skt0, st.skt1local v0, v1 = bu >> 32, bu & 4294967295local sum, delta = 0, 2654435769for i = 1, ROUNDS dov0 = v0 + ((v1 << 4 ~ v1 >> 5) + v1 ~ skt0[i]) & 4294967295v1 = v1 + ((v0 << 4 ~ v0 >> 5) + v0 ~ skt1[i]) & 4294967295endbu = v0 << 32 | v1return bu
end
local enc = function(key, iv, itxt)assert(#key == 16, "bad key length")assert(#iv == 8, "bad IV length")if #itxt == 0 thenreturn ""endlocal ivu = sunpack("<I8", iv)local ot = {}local rbn = #itxtlocal ksu, ibu, oblocal st = keysetup(key)for i = 1, #itxt, 8 doksu = encrypt_u64(st, ivu ~ i)if rbn < 8 thenlocal buffer = string.sub(itxt, i) .. string.rep("\000", 8 - rbn)ibu = sunpack("<I8", buffer)ob = string.sub(spack("<I8", ibu ~ ksu), 1, rbn)elseibu = sunpack("<I8", itxt, i)ob = spack("<I8", ibu ~ ksu)rbn = rbn - 8endapp(ot, ob)endreturn concat(ot)
end
function check_login(username, password)local encoded = base64.encode(username)if encoded ~= "TDNIX1NlYw==" then --L3H_Secreturn falseendusername = username .. "!@#$%^&*("local x = base64.encode(enc(username, "1qazxsw2", password))if x == "LKq2dSc30DKJo99bsFgTkQM9dor1gLl2rejdnkw2MBpOud+38vFkCCF13qY=" thenreturn trueendreturn false
end

仔细看了一下加密的原理,发现前面虽然很复杂是tea-cbc但其实最后还是异或,所以直接在解出的lua脚本里敲个print,dump出要异或的字节流就可以了。

from base64 import b64decodecmp = b64decode('LKq2dSc30DKJo99bsFgTkQM9dor1gLl2rejdnkw2MBpOud+38vFkCCF13qY=')
print(len(cmp)) # 44
a = [
48256960675354976,
-4890521267755574343+2**64,
4792028846500240997,
9087511422306731418,
7661124995518270764,
-4844959183373908412+2**64
]
ba= list(b''.join(map(lambda x: x.to_bytes(8,"little"),a)))
for i in range(44):print(chr(cmp[i]^ba[i]),end='')

2021L3HCTF luuuuua Writeup相关推荐

  1. 2021年中国工业互联网安全大赛核能行业赛道writeup之usb流量分析

    目录 一.USB协议 二.键盘流量 三.鼠标流量 四.writeup 附件题:usb流量分析 题目描述: 具体描述忘记了o(╯□╰)o 大概意思是有个U盘插到电脑上,然后经过一些操作导致该电脑重启了. ...

  2. 2021年中国工业互联网安全大赛核能行业赛道writeup之鱿鱼游戏

    目录 一.尝试 二.Writeup 附加题 鱿鱼游戏(来自最近一部很火的韩剧) 题目描述: 小王由于操作不规范,误将不明U盘插入到上位机中,导致上位机中的某些关键文件被加密,但攻击者在U盘中还留下了一 ...

  3. 2018湖湘杯海选复赛Writeup

    2018湖湘杯Writeup 0x01 签到题 0x02 MISC Flow 0x03 WEB Code Check 0x04 WEB Readflag 0x05 WEB XmeO 0x06 Reve ...

  4. php upload ctf,强网杯CTF防御赛ez_upload Writeup

    这是强网杯拟态防御线下赛遇到的web题目,本来是不打算分享Writeup的,但是由于问的人很多,于是这里分享给大家. ez_upload这题算是非常经典的堆叠black trick的题目,算是比较典型 ...

  5. 安恒赛php_安恒11月月赛周周练writeup

    前言 11月月赛 完美错过时间,正好有周周练,基本都是一样月赛的web,记录下write up 手速要快 这题是10月月赛中的一题,直接看我上次的writeup:安恒月赛(十)web-2题writeu ...

  6. 南京邮电大学网络攻防训练平台(NCTF)-异性相吸-Writeup

    南京邮电大学网络攻防训练平台(NCTF)-异性相吸-Writeup 题目描述 文件下载地址 很明显,文件之间进行亦或就可得到flag,不再多说,直接上脚本 1 #coding:utf-8 2 file ...

  7. 社团的CTF逆向题WriteUp

    最近社团弄了CTF比赛,然后我就帮忙写了逆向的题目,这里写一下WriteUp,题目和源码在附件中给出 一个简单的逆向:one_jmp_to_flag.exe 这题算是签到题,直接OD智能搜索就完事了, ...

  8. CTF-i春秋网鼎杯第一场misc部分writeup

    CTF-i春秋网鼎杯第一场misc部分writeup 最近因为工作原因报名了网鼎杯,被虐了几天后方知自己还是太年轻!分享一下自己的解题经验吧 minified 题目: 一张花屏,png的图片,老方法, ...

  9. NCTF2019 -- PWN部分writeup

    pwn学习总结(二) -- PWN部分writeup warmup easy_rop warmup 查看程序防护: 查看反汇编: 已知条件: 开启了溢出检测 开启了沙盒模式,只能调用libc中的ope ...

  10. 攻防世界-web-shrine-从0到1的解题历程writeup

    题目环境分析 首先开启靶机获取到题目如下 import flask import os app = flask.Flask(__name__) app.config['FLAG'] = os.envi ...

最新文章

  1. 用python打开视频_python读取视频流提取视频帧的两种方法
  2. 终于有人把 Nginx 说清楚了,图文详解!
  3. linux下miniconda3启动命令
  4. Nagios Apache报Internal Server Error错误的解决方法
  5. 面试题:谈谈你对hibernate的理解
  6. mysql查询含有某个值的表_MYSQL查询数据表中某个字段包含某个数值
  7. 飞鸽传书写每行都认认真真
  8. linux 文件句柄 sock,tcp socket文件句柄泄漏
  9. vs2019MSDN(离线帮助文档)的下载与使用
  10. LoadRunner压力测试:测试报告结果分析
  11. 《乌合之众》思维导图
  12. Hexo next 主题加载自定义 js 文件
  13. 嵌入式设备引入机器学习:有eIQ就够了!
  14. 使用python做手机app后台
  15. excel拆分表格之多条件拆分
  16. 学习游戏服务器开发必看,C++游戏服务器开发常用工具介绍
  17. ViewPager添加小圆点
  18. android 熄屏 后台运行,Android进程保活/息屏后后台保持定位、网络运行
  19. 【excel精度丢失】excel计算会有精度丢失么?答案:会
  20. ABAP编程语言-概览

热门文章

  1. # AD19规则设置的傻瓜式教程
  2. jsp物流配送管理系统
  3. windows下Mysql 5.7 绿色版安装与卸载教程,MySQL可视化管理
  4. CentOS 6.0 安装 Atheros ar8151 网卡驱动
  5. Java学习代码合集
  6. 如何让百度云里的资源不被和谐掉?
  7. c#oracle数组超出,急问:System.IndexOutOfRangeException: 索引超出了数组界限解决方案
  8. 选择RDP报表工具的原因
  9. Latex英文论文模板汇总(elsevier、arXiv、IEEE Access)
  10. 能源管理模式数字化,引导未来能源服务新方向!