首页
DST服务器列表
关于
推荐
AI深度搜索
Search
1
庄子的回文——从零开始的入门级64位ROP
1,132 阅读
2
Windows沙盒——运行不安全的软件
836 阅读
3
重温《幽灵公主》:成年后的理性视角与沉浸体验的界限
14 阅读
研究笔记
技术文档
工具推荐
网络安全
心理学
生活小记
登录
/
注册
Search
标签搜索
binary
64位
ROP
pwn
吉卜力
电影
libero
累计撰写
3
篇文章
累计收到
14
条评论
首页
栏目
研究笔记
技术文档
工具推荐
网络安全
心理学
生活小记
页面
DST服务器列表
关于
推荐
AI深度搜索
搜索到
3
篇与
的结果
2025-05-02
重温《幽灵公主》:成年后的理性视角与沉浸体验的界限
2025年5月1日,我重温了宫崎骏的《幽灵公主》。预期中或许有怀旧的温情,但实际体验却大相径庭。故事梗概与理性观察客观来看,《幽灵公主》描绘了一场多方冲突:代表人类工业力量、掠夺自然资源的炼铁场;守护森林、代表古老自然的山犬族、野猪族与山兽神;被卷入其中的主角阿席达卡与幽灵公主桑;妄图夺取山兽神头颅的和尚;代表朝廷力量剥削普通民众的武士。每个派系都基于自身的立场、欲望和生存法则行动,冲突不断升级,最终导致了各方力量严重受损的结局——一种“自损八百”的必然。作为成年观众,我并未感受到孩童时期可能体会到的那种纯粹的“好看”或冒险的乐趣。然而,也并非无聊。我的注意力自然地转向了分析:解构各个派系的动机,梳理他们之间不可调和的矛盾,以及冲突带来的毁灭性后果。我能通过配乐感知到导演试图传达的无奈,主角力量在派系力量面前的挣扎,从结局中解读出对新生的希望——但这更多是一种智力层面的主题识别,而非直接的情感共鸣。我尝试“读懂”这个故事,想概括这个故事想表达的主题,最终得到的结论是我并不想强行给这个故事赋予任何主题,如果你没有看过这部电影,或许代入主角的视角自然而然的享受故事才是最好的。一个有趣的发现:理性与幻想的边界观影过程中,一个有趣的念头浮现:我能清晰地通过理性认知到,如果我还是个孩子,我大概率会沉浸其中——我会幻想阿席达卡和桑未来的生活,憧憬自己也能与神秘的大自然有场奇遇。我会单纯的期待故事的走向,结束时还会有一些故事意犹未尽的感伤,不过这种纯粹的、代入式的幻想能力,在现在的我看来似乎已经让位于分析和解构的冲动,不过这很正常,这也似乎并不是我个人的性格特质,而是因为人总是会长大的,长大之后人就会本能的寻找所谓的电影主题和意义,不会那么天真的想象一个童话世界。但我突然想到我玩《原神》似乎能得到孩童时代的视角,在游戏中,作为主动参与的“旅行者”,我更容易代入角色去感受故事,游戏的节奏更慢,需要我们去进行交互,游戏对角色的背景和性格特质交代的更加丰满,我们更容易体验角色的情感和旅程。这种参与感似乎能暂时关闭那个不断寻求宏大意义和逻辑结构的分析引擎,允许我更多地沉浸在当下。相比之下,作为电影的外部观察者,我的分析模式更容易被触发,去审视结构、主题和象征意义,这或许就是游戏被称为第九艺术的原因,它确实能通过更丰富的交互手段,让人抛弃观察者视角去以故事里面的角色视角来获得不同的体验。结语这次观影体验清晰地照见了一个转变:从孩童时期可能追求的沉浸式体验,到成年后更倾向于理性分析和意义解读。这并非优劣之分,而是认知模式随成长自然发生的变化。认识到这一点,有助于我们理解自己与不同故事、不同媒介互动时的差异,以及为何某些体验能触动我们内心不同的层面。
2025年05月02日
14 阅读
0 评论
0 点赞
2021-06-15
庄子的回文——从零开始的入门级64位ROP
背景介绍前段时间,我们学校组织了一场校内的以推广CTF赛事为主的网络安全比赛。当时其实并没有很想参加,不过在舍友的安利之下 ::(汗),我于第二天加入了内卷洪流之中。 不过出乎意料的,比赛的赛题设计的很有意思,也很适合我这种网络安全知识面比较广但是没做过实操的人。就这样我开启了我的网络安全修炼之路。比赛过程中,我所用到的大部分的知识都属于现学现卖,最终也是取得了不错的成绩,于是,我也有了写博客的想法。希望能为后人种一种树。本篇文章作为入门级Pwn赛题的讲解,只需读者掌握部分计算机学科基础知识即可。本篇文章只关注入门的内容,如果你是高手可能会觉得很无聊。Pwn是什么?通常是要利用程序中的特定漏洞,构造特定字符串(也称payload)输入程序中,以达到控制目标主机的目的。通常这种题目都相当直白,直接扔给你一份编译后的可执行程序,然后给你一个ip地址和端口,这个端口上跑的就是这个可执行程序,你要做的就是在本地分析出这个可执行程序中存在的漏洞,并且巧妙构造一份字符串,输入给这个端口,然后如果构造正确的话,就可以利用这个端口控制远程主机。发现漏洞一般都是比较简单的事情,然而,想要利用这个漏洞控制远程主机,需要非常心灵手巧才行 :@(暗地观察) 。因此这类题上手难度较大,不过一旦成功往往会有一种巨大的成就感。题目{card-default label="庄子的回文" width=""}在《庄子》中,逍遥而遊的自由存在内蕴着一个逍遥主体与 Flag 之间的深刻而复杂的关系,这一关系必须置于一个回文过程中来理解。逍遥作为艰苦的历程,其要义在于它经由对自身的出离而与异于自身的他者相遇,并与他者共同构成彼此相聚的整体,在此整体中确证自身且返回自身。《庄子》对逍遥的诗意言说方式本身,并不掩盖逍遥观念自身的过程本质。撇开了如此艰苦的历程,逍遥就会成为毫无内容的仅仅溢于言表的虚幻的托辞。逍遥必须回到其艰苦而丰富的展开过程,才是真实的。 ——郭美华请把字符串交给庄子,设法让庄子在计算回文串时,在服务器上执行代码或命令,读取文件系统中某处存储的 Flag。你可以 下载本题的程序点击 “打开/下载题目” 将打开网页终端,你也可以通过命令 nc prob05.geekgame.pku.edu.cn 10005 手动连接到题目PS: 上述指令其实就是和prob05.geekgame.pku.edu.cn的10005端口建立TCP连接,因为服务器可能关闭,所以上述IP端口可能失效{/card-default}做出本题需要掌握的知识{message type="info" content="1、x86汇编及部分x64汇编知识2、python语言及pwntools的基本用法3、gdb动态调试和ida静态调试4、C语言和Linux操作系统的基本知识"/}程序安全保护信息与实验环境{collapse}{collapse-item label="程序安全保护信息" open} 以下是程序安全保护信息,用checksec指令进行查看: ❗ 本题程序没有开启CANARY保护{/collapse-item}{collapse-item label="实验环境" open}主机:Win10 专业版 19042.1052虚拟机:Kali Linux 2021.1 amd64{/collapse-item}{/collapse}IDA的简单使用——反汇编和反编译可执行文件首先需要下载一个静态分析利器ida,这个软件可以对可执行文件进行反汇编,甚至可以反编译成比较容易看懂的C语言代码。这里给出一个下载链接,读者可根据自身需要选择: {anote icon="fa-download" href="https://www.jb51.net/softs/757010.html" type="secondary" content="IDA Pro 7.5破解版"/}安装成功后,主要有两个程序,一个是IDA Pro 7.5 SP3,另一个是IDA Pro 7.5 SP3 x64,前者是用来分析32位可执行文件的,后者是用来分析64位可执行文件的。一般先用IDA Pro 7.5 SP3 x64,它会提示你可执行文件是64位还是32位的,打开它,点击new,选择要分析的可执行文件,把本题的程序解压出来,选择pwn这个文件。{gird column="2" gap="15"}{gird-item} {/gird-item}{gird-item} {/gird-item}{/gird}然后软件会叫你选择文件的加载方式,这里什么都不用改,直接点OK就行,注意这里IDA识别出来了这个可执行文件的类型是ELF64 for x86-64,ELF是Linux下主要的可执行文件的文件格式,x86-64则代表该可执行文件是64位的:左边列出了该程序中所有的函数,包括程序内部定义的和链接外部的。我们选择main函数,先看看主函数:右边是main函数反汇编的结果,为了舒服我们一般都再反编译成C语言,摁下F5即可:int __cdecl main(int argc, const char **argv, const char **envp) { int v5; // [rsp+Ch] [rbp-4h] BYREF setbuf(stdout, 0LL); setbuf(stderr, 0LL); banner(); __isoc99_scanf("%d", &v5); while ( v5-- ) run(); return 0; }双击banner和run可以看到banner和run子函数的代码:可以看到banner这里给了一个提示,告诉你本题的程序其实是百练上一道上机题的解B:回文子串。int banner() { printf("This is a solution for this problem: %s\n", "http://bailian.openjudge.cn/xlylx2019/B/"); return puts("PWN it!"); }int run() { char s[104]; // [rsp+0h] [rbp-80h] BYREF int v2; // [rsp+68h] [rbp-18h] int k; // [rsp+6Ch] [rbp-14h] int j; // [rsp+70h] [rbp-10h] int i; // [rsp+74h] [rbp-Ch] int v6; // [rsp+78h] [rbp-8h] int v7; // [rsp+7Ch] [rbp-4h] __isoc99_scanf("%s", s); v2 = strlen(s); v6 = 0; for ( i = 0; i < v2; ++i ) { for ( j = i + 1; j <= v2; ++j ) { if ( (unsigned int)check(&s[i], (unsigned int)(j - i)) && v6 < j - i ) { v6 = j - i; v7 = i; } } } for ( k = v7; k < v7 + v6; ++k ) putchar(s[k]); return putchar(10); }至此,我们利用IDA工具成功获取了可执行程序的反编译代码,可以对程序逻辑进行分析了,因为编译过程中,会抹去变量名、函数名、部分结构信息等,所以反编译后的代码看起来会和我们正常写的不一样。细心的读者可能会发现题目给的另一个文件libc-2.31.so,这个文件的作用类似于Windows的dll文件,作为动态链接库向pwn提供库函数,接下来我们先讲解栈溢出漏洞的原理,这个文件将在之后的漏洞利用中登场。函数调用栈与栈溢出漏洞对于函数调用栈,比较细致的讲解可参考这篇文章: 手把手教你栈溢出从入门到放弃(上)。这里以比较通俗的文字给读者一个函数调用栈的基本映像。我们在调用函数的时候,函数内部可能又去调用其他函数,然后再回过头来继续执行,我们把外部函数称为父函数,内部函数称为子函数,因为要确保子函数执行完毕后,我们能继续执行父函数,那么我们需要保存父函数的地址、父函数的局部变量的值等父函数的状态信息,这时候栈这种结构就派上了用场,因为函数的多级调用是一个先入后出的行为,即越先被调用的函数越后执行完毕,这和栈的性质是对应的。当我们要执行子函数时,就把父函数的状态信息保存在栈中,然后再栈中分配新的空间给子函数,待执行完毕之后pop掉子函数的状态恢复父函数的状态继续执行就行了。因为接下来对于一些细节的讲解必须涉及到汇编,这里为不熟悉汇编的读者准备了一些讲解,可点开查看:{collapse}{collapse-item label="汇编基础知识"}BP、SP和IP寄存器寄存器主要是用来存储临时数据的,所谓临时就是值会经常发生改变。这里介绍一下和函数调用栈相关的特殊寄存器。RBP、EBP、BP其实都是指向一个长度为64位的寄存器,只不过RBP代表这个寄存器的全部64位,EBP代表低32位,BP代表低16位,如果是32位操作系统,就没有RBP,只有EBP和BP。同理SP和IP也是这种规则。RBP存储的可以理解成是当前执行函数状态的起始地址,RSP存储的是当前函数调用栈中最后一个元素的有效地址,也就是栈顶的位置。{message type="warning" content="注意因为函数调用栈从高地址往低地址增长的,所以其实栈顶的地址是最低的地址,也就是RSP中存储的地址<=RBP中存储的地址"/}RIP寄存器存储的是当前执行指令的地址,可以利用跳转指令来修改RIP的值,使其跳转到system或exec等函数执行一些可以入侵到目标主机的代码,比如说system("/bin/sh"),这也是Pwn题的最终目标。PUSH和POP指令PUSH指令就是将操作数压入栈中,具体就是先减小RSP的值,然后把操作数赋值到RSP指向的地址。例如PUSH EBP。POP指令就是将栈顶的元素弹出来,赋值给操作数。例如POP EBP。MOV指令通常写作MOV DST, SRC即将SRC的值赋值给DST,某些时候也会写成MOV SRC, DST。CALL、JMP和RET指令CALL指令先把RIP的值压入栈中,然后跳转到操作数指向的地址。JMP指令直接跳转到操作数指向的地址,即把操作数的值赋值给RIP。RET指令从栈顶中取出地址赋值给RIP。{/collapse-item}{/collapse}接下来我们来用通俗的语言解释一次子函数调用的过程:{mtitle title="子函数调用的过程"/}{timeline}{timeline-item color="#19be6b"} 父函数准备子函数的参数:在32位操作系统中,会用PUSH指令,从右到左,依次把子函数的实参压入栈中;在64位操作系统中,优先用寄存器传递参数,子函数的实参从左到右会被赋值给RDI、RSI、RDX、RCX、R8和R9寄存器,如果还有更多参数才会PUSH到栈上。{/timeline-item}{timeline-item color="#19be6b"} 执行CALL指令调用子函数:先把RIP的值压入栈(也就是父函数下一条指令的地址),然后将子函数第一条指令所在的地址赋值给RIP实现跳转。{/timeline-item}{timeline-item color="#409eff"} 保存父函数的EBP:PUSH EBP{/timeline-item}{timeline-item color="#409eff"} 当前栈顶作为子函数的EBP:MOV EBP, ESP{/timeline-item}{timeline-item color="#409eff"} 执行子函数的逻辑......直到执行完毕{/timeline-item}{timeline-item color="#409eff"} 保存子函数的返回值:用RAX寄存器保存子函数的返回值,用MOV指令把返回值赋值给RAX{/timeline-item}{timeline-item color="#409eff"} 恢复父函数的EBP:POP EBP{/timeline-item}{timeline-item color="#409eff"} 返回父函数:RET(从堆栈中取出之前保存的父函数返回地址赋值给RIP){/timeline-item}{timeline-item color="#19be6b"} 继续执行父函数的代码......{/timeline-item}{/timeline}函数调用栈用一张图表示为(图片引用自手把手教你栈溢出从入门到放弃(上)):{message type="info" content="1、Caller代表父函数,Callee代表子函数2、arg代表子函数的参数3、Local Variables为子函数的局部变量"/}所谓栈溢出,就是让局部变量的值覆盖掉Return Address,使得子函数返回的时候跳转到特定的地址执行一些危险代码。那么,怎么局部变量的值覆盖掉Return Address呢?因为C语言不检查数组的索引是否越界,因此这一点经常被利用来实现栈溢出攻击。在本题中,我们注意到run函数中有一个__isoc99_scanf函数(其实就是scanf函数)读入数据到局部变量s上:字符串读入的时候,是从低地址到高地址依次赋值的,因此只要输入的字符串够长,就可以覆盖掉Return Address:ROP与栈溢出漏洞的利用ROP中文名是面向返回的编程,顾名思义就是利用已有的动态链接库和可执行文件,提取出可以利用的指令片段(gadget),这些指令片段均以RET指令结尾,即用RET指令实现指令片段执行流的衔接(前面提到过RET会把栈顶的元素赋值给RIP),最后完成期待的恶意行为。我们最终的目的是让程序执行一个可以控制shell的代码片段(gadget),那么怎么知道这种代码片段所在的位置呢?这里可以利用一个one_gadget工具,下载方法为:sudo apt -y install ruby sudo gem install one_gadget用起来也很简单,pwn中是不可能有这种函数的,只能在libc-2.31.so中找:one_gadget libc-2.31.so然后工具会告诉你有哪些可以控制目标主机的代码片段,这些代码片段的位置,以及需要满足的条件:这里我们就利用0xe6c7e这个位置的gadget,注意限制条件是:对于r15,要么r15保存的这个地址指向0,要么r15本身是0。对于r12,要么r12保存的这个地址指向0,要么r12本身是0.为便于说明,下面我们称上面这个代码片段为gadget1。有了控制目标主机的gadget,怎么才能跳转到它并满足上述限制条件呢,可分为两步:因为目标主机可能开启了ASLR(即每次运行程序,栈的地址和动态链接库的地址随机变化),所以我们首先要设法得到gadget1在内存中的位置(上面那个0xe6c7e只是个相对地址),这里主要利用这样一个性质:.so文件中两个函数的相对地址(即两个地址的差)和加载到内存中的相对地址是一样的。其次我们需要一段gadget来控制r15和r12寄存器的值。对于第一步,我们需要调用.so文件中的puts函数,打印出某个函数在内存中的地址,并据此计算出相对地址,所以我们需要控制rdi寄存器的值(也就是控制puts函数的参数),在pwn程序中搜索寄存器的名称就能发现下面这一段代码:0x4013ba后面这一段代码可以控制rbx、rbp、r12、r13、r14、r15寄存器的值,0x4013a6则可以控制edi寄存器的值。攻击载荷的巧妙构造目前,我们需要的gadget都已经找齐,接下来就只需要巧妙的构造攻击载荷,让程序最终执行到gadget1。具体来讲,首先需要控制程序,打印出.so中某个函数的地址,然后我们可以计算出函数加载到内存前后的相对位置,然后可以据此计算出当前内存中的gadget1的位置,然后再让程序跳转到这个地址。Step1: 获得相对地址下面这张图展示的攻击载荷将会使程序打印出当前内存中printf函数的地址:程序会先跳转到0x4013ba,然后将rbx的值修改为1,rbp的值修改为2,以此类推,然后程序会跳转到0x4013a6,并修改edi的值,然后执行call指令,调用我们指定的puts函数,为了让程序不至于崩溃,我们最后控制它返回到了main函数。用该地址减去.so文件中printf函数的地址,得到的就是函数加载到内存前后的相对地址。Step2: 跳转到gadget1和Step1类似,先跳转到0x4013ba控制r12和r15寄存器的值,然后跳转到0xe6c7e即可。最后成功入侵系统的截图:{anote icon="fa-download" href="https://www.liuyh.com/usr/uploads/2022/02/493363414.txt" type="success" content="参考代码"/}最后pwn题是CTF比赛非常常见的题型,对于初学者来讲,因为解题涉及到太多需要实操的底层知识,上手难度会比较大,但实际上对于较强的选手来说,这类题型因为出题的套路不是很多,所以反而做起来比较容易。希望通过这篇文章能让读者对这类题型有个初步的认识。
2021年06月15日
1,132 阅读
0 评论
4 点赞
2021-06-14
Windows沙盒——运行不安全的软件
Introduction做网络安全的一大特点就是工具种类特别杂,很多还是要License的,没办法,总不可能全都买下吧,很多时候只能去用破解版的软件。但是经常破解版的软件一解压就报病毒,这时候那叫一个投鼠忌器。了解一番后,发现Windows沙盒这个东西,今天就来试用一下。Windows官方文档直达环境要求Win10 64位专业版/企业版/教育版 build 18301预览版及以上版本安装方式Win10左下角搜索启用或关闭Windows功能,进去后勾选Windows沙盒,点确定重启系统。运行示例正好,最近打CTF,要用一款软件ForensicDiskDecryptor。粘贴进去:按照安下载的教程,破解成功了,诚不欺我。正常在Windows下打开Windows Defender的会报病毒的。以我本科对恶意软件的一点研究,Windows Defender还是挺严格的,只要不作死正常使用电脑应该不会中毒。而Windows沙盒就提供了一个无Windows Defender的环境,而且跑程序也是以管理员身份运行的,关闭以后一切ByeBye~(关了会自动删除所有文件),想跑啥跑啥,很舒服。
2021年06月14日
836 阅读
3 评论
0 点赞