记一次在线学习平台的漏洞利用

记一次在线学习平台的漏洞利用

注:此漏洞已汇报给IT,已被修复

目录

  1. 漏洞介绍
  2. 具体实现
  3. 整体实现代码

漏洞介绍

在线学习平台study.test***.cn中SAT题卡允许用户重复提交,且提交后可获得错题报告,因此可以通过填3次题卡通过报告推出正确选项然后填第4次提交。但由于在提交一次后系统不允许再从主页面创建题卡的句柄,只有创建多个句柄后依次填卡提交才能利用此漏洞。此漏洞可以人为在浏览器中操作利用,但由于人工填4张卡和推到正确选项过于费时,利用脚本模拟浏览器操作更高效。

具体实现

使用了Python + Selenium模拟浏览器操作,xpath解析HTML

获取页面

对应代码如下:

chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--disable-gpu')
browzer = webdriver.Chrome(options=chrome_options)
login_url = 'https://study.test***.cn'
browzer.get(login_url)
登陆

找到用户名输入框 -> 输入用户名 -> 找到密码框 -> 输入密码 -> 回车
对应代码如下:

user_name = '******'
password = '******'
browzer.find_element_by_id('username').send_keys(user_name)
browzer.find_element_by_id('password').send_keys(password)
browzer.find_element_by_xpath('//body').send_keys(Keys.ENTER)
找到题卡

系统提供了搜索功能,所以可以 找到搜索框 -> 输入题卡名称
对应代码如下:

search_kw = input('Task name:  ')
browzer.find_element_by_xpath('//input[@placeholder="Search…"]').send_keys(search_kw)
创建四个题卡句柄

点击“开始”按钮为创建一个题卡句柄
加上等待以防阻塞
对应代码如下:

browzer.find_element_by_xpath('//span[@title="开始任务"]').click()
time.sleep(4)
browzer.find_element_by_xpath('//span[@title="开始任务"]').click()
time.sleep(4)
browzer.find_element_by_xpath('//span[@title="开始任务"]').click()
time.sleep(4)
browzer.find_element_by_xpath('//span[@title="开始任务"]').click()
time.sleep(4)
填卡推答案然后填第四张卡

此时一共有五个句柄。第0个是主页面,1-4个是题卡句柄。

切换到句柄1 -> 全填A -> 提交 -> 分析报告 -> 结果存入字典
*填卡是通过找到选项单元格元素然后点击
*提交是指找到提交按钮并且点击
*分析报告是找出正确(没有红叉)的题目
*存入字典是指把正确的答案存入字典
切换到句柄2 -> 全填B -> 提交 -> 分析报告 -> 结果存入字典
切换到句柄3 -> 全填C -> 提交 -> 分析报告 -> 结果存入字典
整理字典,字典中没有答案的题答案为D (因为前面A,B,C都试过了)
切换到句柄4 ,用字典中的答案填卡 -> 提交 -> 满分SAT模考诞生;但很明显真实的做满分不太可能(对我来说),因此为了成功欺骗老师可以通过一些社工手段,即部分随机错误答案来达到自己想要的正确率。

对应代码如下:

CorrectAnswerlist = {}

for trial_t in range(3):
    print(CorrectAnswerlist)
    browzer.switch_to.window(browzer.window_handles[1 + trial_t])
    time.sleep(2)

    if trial_t == 0:
        card_body = browzer.find_element_by_xpath('//div[@class="ant-card-body"]').get_attribute('innerHTML')
        # Get number range
        html = etree.HTML(card_body)
        etree.tostring(html, encoding= 'utf-8')

        q_nums = html.xpath('//div[contains(@class,"ant-col-4")]/text()')
        q_nums = [int(i) for i in q_nums]
        # print(q_nums)

    choice = {'1' : 'A', '2' : 'B', '3' : 'C', '4' : 'D'}[str(trial_t + 1)]
    for q_ind in q_nums:
        browzer.find_element_by_xpath('//div[@class="ant-card-body"]//div[contains(@class, "ant-col-4") and text()="' + str(q_ind) + '"]/../div[contains(@class, "ant-col-16")]//span[text()="' + choice + '"]').click()
    browzer.find_element_by_xpath('//span[text()="提交答题卡"]/..').click()
    time.sleep(4)
    browzer.find_element_by_xpath('//div[@class="ant-modal-confirm-btns"]//span[text()="提交答题卡"]/../..').click()

    time.sleep(4)

    card_body = browzer.find_element_by_xpath('html').get_attribute('innerHTML')

    # 找 class="ant-col ant-col-xs-4 ant-col-sm-3 ant-col-md-3" 的div的个数,那么(n/2)个到最后就是

    print(card_body)
    html = etree.HTML(card_body)
    etree.tostring(html, encoding= 'utf-8')

    roots = html.xpath('//div[@class="ant-col ant-col-xs-4 ant-col-sm-3 ant-col-md-3"]')

    for i in range(len(q_nums)):
        ToF = roots[len(q_nums) + i].xpath('div[2]//svg/@height')
        if len(ToF) == 0:
            CorrectAnswerlist.update({str(q_nums[i]) : choice})

for q_ind in q_nums:
    if str(q_ind) not in CorrectAnswerlist:
        CorrectAnswerlist.update({str(q_ind) : 'D'})

browzer.switch_to.window(browzer.window_handles[4])
time.sleep(4)

print(CorrectAnswerlist)

# Fill the card, with expected error rate
# Here is 0.25. 
for q_ind in q_nums:
    if random.random() > 0.25: # To make it 100% correct, use -1
        choice = CorrectAnswerlist[str(q_ind)]
    else:
        aaa = random.random()
        if aaa < 0.25:
            choice = 'C'
        elif aaa < 0.5 and aaa > 0.25:
            choice = 'D'
        elif aaa < 0.75 and aaa > 0.5:
            choice = 'A'
        else:
            choice = 'B'

    browzer.find_element_by_xpath('//div[@class="ant-card-body"]//div[contains(@class, "ant-col-4") and text()="' + str(q_ind) + '"]/../div[contains(@class, "ant-col-16")]//span[text()="' + choice + '"]').click()
browzer.find_element_by_xpath('//span[text()="提交答题卡"]/..').click()
time.sleep(4)
browzer.find_element_by_xpath('//div[@class="ant-modal-confirm-btns"]//span[text()="提交答题卡"]/../..').click()
time.sleep(6)

整体实现代码

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
from lxml import etree
import random

chrome_options = webdriver.ChromeOptions()
# chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')

browzer = webdriver.Chrome(options=chrome_options)

login_url = 'https://study.test***.cn'
user_name = '******'
password = '******'

browzer.get(login_url)

browzer.find_element_by_id('username').send_keys(user_name)
browzer.find_element_by_id('password').send_keys(password)
browzer.find_element_by_xpath('//body').send_keys(Keys.ENTER)

time.sleep(4)

search_kw = input('Task name:  ')
browzer.find_element_by_xpath('//input[@placeholder="Search…"]').send_keys(search_kw)

time.sleep(4)

browzer.find_element_by_xpath('//span[@title="开始任务"]').click()
time.sleep(4)
browzer.find_element_by_xpath('//span[@title="开始任务"]').click()
time.sleep(4)
browzer.find_element_by_xpath('//span[@title="开始任务"]').click()
time.sleep(4)
browzer.find_element_by_xpath('//span[@title="开始任务"]').click()
time.sleep(4)

time.sleep(2)
print(browzer.window_handles)
CorrectAnswerlist = {}

for trial_t in range(3):
    print(CorrectAnswerlist)
    browzer.switch_to.window(browzer.window_handles[1 + trial_t])
    time.sleep(2)


    if trial_t == 0:
        card_body = browzer.find_element_by_xpath('//div[@class="ant-card-body"]').get_attribute('innerHTML')
        # Get number range
        html = etree.HTML(card_body)
        etree.tostring(html, encoding= 'utf-8')

        q_nums = html.xpath('//div[contains(@class,"ant-col-4")]/text()')
        q_nums = [int(i) for i in q_nums]
        # print(q_nums)

    choice = {'1' : 'A', '2' : 'B', '3' : 'C', '4' : 'D'}[str(trial_t + 1)]
    for q_ind in q_nums:
        browzer.find_element_by_xpath('//div[@class="ant-card-body"]//div[contains(@class, "ant-col-4") and text()="' + str(q_ind) + '"]/../div[contains(@class, "ant-col-16")]//span[text()="' + choice + '"]').click()
    browzer.find_element_by_xpath('//span[text()="提交答题卡"]/..').click()
    time.sleep(4)
    browzer.find_element_by_xpath('//div[@class="ant-modal-confirm-btns"]//span[text()="提交答题卡"]/../..').click()

    time.sleep(4)

    card_body = browzer.find_element_by_xpath('html').get_attribute('innerHTML')

    # 找 class="ant-col ant-col-xs-4 ant-col-sm-3 ant-col-md-3" 的div的个数,那么(n/2)个到最后就是

    print(card_body)
    html = etree.HTML(card_body)
    etree.tostring(html, encoding= 'utf-8')

    roots = html.xpath('//div[@class="ant-col ant-col-xs-4 ant-col-sm-3 ant-col-md-3"]')

    for i in range(len(q_nums)):
        ToF = roots[len(q_nums) + i].xpath('div[2]//svg/@height')
        if len(ToF) == 0:
            CorrectAnswerlist.update({str(q_nums[i]) : choice})
        
print(CorrectAnswerlist)

for q_ind in q_nums:
    if str(q_ind) not in CorrectAnswerlist:
        CorrectAnswerlist.update({str(q_ind) : 'D'})

browzer.switch_to.window(browzer.window_handles[4])
time.sleep(4)

print(CorrectAnswerlist)

for q_ind in q_nums:
    if random.random() > 0.25:
        choice = CorrectAnswerlist[str(q_ind)]
    else:
        aaa = random.random()
        if aaa < 0.25:
            choice = 'C'
        elif aaa < 0.5 and aaa > 0.25:
            choice = 'D'
        elif aaa < 0.75 and aaa > 0.5:
            choice = 'A'
        else:
            choice = 'B'

    browzer.find_element_by_xpath('//div[@class="ant-card-body"]//div[contains(@class, "ant-col-4") and text()="' + str(q_ind) + '"]/../div[contains(@class, "ant-col-16")]//span[text()="' + choice + '"]').click()
browzer.find_element_by_xpath('//span[text()="提交答题卡"]/..').click()
time.sleep(4)
browzer.find_element_by_xpath('//div[@class="ant-modal-confirm-btns"]//span[text()="提交答题卡"]/../..').click()

time.sleep(6)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值