开始
上周末在驾校练车中,收到朋友的消息,说最近发现一个宝藏软件,仔细了解之后发现,他口中的宝藏软件也就是一个有色的漫画软件,不过作为资深二次元的他,在他认为是宝藏软件的应该有点东西。我安装之后发现果然是个”好东西“,噗哈哈,资源多,无广告。
然后重点来了,这个软件是要会员的,他的需求是能不能让我破解一下,啊这!我又不是搞移动端软件开发的,咋破解!不过我还是对这个软件分析了一波,分析之后让我深深的鄙视了一番这个软件的作者。
分析
首先打开软件,发现这个软件主体就是漫画展示,除此之外也没别的。然后第二个tab是漫画的分类,有全部、校园、真人…在全部中,向上滑动可加载更多的漫画,我试着滑了几波,发现漫画还挺多,也不见底。于是惯例打开抓包软件试试能不能从这找到突破口,通过抓包发现,这个软件的数据传输没有做任何的防护加密,SSL没有,对数据内容的加密也没有,就是赤裸裸的展示着,响应回来的就是json数据。
全部漫画分页接口
请求地址:http://******.***/e/extend/api/index.php?type=cartoon&paged=true&size={}&page={}&filter=id
后来通过分析得知,虽然这个接口地址发出的是post请求,但是复制到浏览器地址栏回车也能得到数据,后端没做严格的判断,而且size参数也没限制,我改成100回车,也会返回100条漫画信息,真垃圾
1 | { |
通过这个接口响应的数据还真能得到不少的信息,漫画果然多一共984本,果然多…然后list数组中展示每一本漫画的详情(名称、作者、简介、封面图、标签、评分等等)。
接着我又点开了一本,发现响应的数据更全,该本漫画的目录都返回过来了。
漫画章节接口
请求地址:http://***.***/e/extend/api/index.php?type=cartoon&filter=directory&bookId={}
通过分析盲猜也知道,地址最后的bookId参数就是上一个接口里漫画的id。下面展示响应的部分json数据
1 | { |
返回的信息也挺全的,章节标题、封面图还有sequence排序字段。
紧接着就是每章节详情页了,这个要是没问题,那么这个软件的所有漫画数据就能被我掏空,噗哈哈。就这?由于大意直到后一天的异常让我知道没有那么简单。
由于这里所有的漫画第一章(漫画术语叫第一话?)都是免费试看的,之后的所有章节都是VIP才能看。于是我先点击这个免费的第一章,然后抓包分析,果然响应回来的数据包含了这张所有的漫画信息。
漫画章节详情接口
请求地址:http://***.***/e/extend/api/index.php?type=cartoon&filter=chapter&bookId={}&chapterId={}
参数中bookId是该本漫画的id,chapterId是上一个接口获取到的章节Id。响应的部分数据如下:
1 | { |
可以看到imageList里url就是漫画的图片,encodeName和url一样,不知道啥意思,同样sequence是排序。
图片的伪装
于是复制了一张图片地址放到浏览器中打开发现不能够打开!WTF?咋回事啊,再次抓包发现软件中请求的图片非原地址,而是把url中图片的格式换成了html,然后返回的数据也不是图片,而是图片的base64编码,哈哈,这也难不倒我,只要没加密啥都好说。
漫画图片原地址:https://******.com/*****/*****/img0-ef11ffe2cf3ef55b73069e16345567fd.png
真实请求的地址:https://******.com/*****/*****/img0-ef11ffe2cf3ef55b73069e16345567fd.html
返回的数据:data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCA......
没啥难的,通过这三个接口完全可以把软件掏空。然后VScode打开,python脚本一把梭。我的思路是根据接口返回的数据取重要的建数据库,存表里,三张表完全够用,一张存漫画主题信息,一张存漫画的目录章节信息,最后一张存章节的详情信息,标准的一对多表结构。
于是代码脚本一顿梭哈,最后大功完成,在爬取得过程中发现了一点异常就是,每一本的漫画除了第一章有很多条详情数据外,之后的每一章都是3条数据,当时我还在心里安慰自己,可能这就是二次元画家的风格吧,每一章只更新一点点。然后也没多想,之后就开始运行脚本了,一切没啥大的异常只是刚开始爬取有一本章节接口返回的500,我在软件中测试该本漫画也是打不开的,吓一跳,以为触发警告,被防爬虫措施ban掉了呢。无关紧要,每次请求后多加了一条判断逻辑,返回非200就continue一下,继续爬取下一个。
就这样一上午就扒干净了该软件的“所有的”资料,之所以所有的加引号,那都是我自以为是的结果。且听我娓娓道来。
在我以为扒干净之后,就开始写下载脚本了,下载的逻辑就是,查询主表,获取各章节,根据各章节获取详情,然后转换真实下载地址,就是那个把后缀改成html的。然后根据返回的base64,再转换成图片,保存到本地中,当然保存到本地文件夹得建好,我的逻辑是每本漫画建一个文件夹,在这个文件夹里每个章节再建一个文件夹,最后再在章节文件夹里存具体的图片。
说时迟那是快,python脚本又一顿梭哈,第一版代码就下好了,我也没急着开始执行爬取。根据原图片地址报错页面得知,这些图片是存在阿里云OSS里的,我就开始了大量的查资料,“OSS有没有防爬取措施?”,“阿里云OSS有没有请求频率的限制?”等等,然而也没搜索啥有用的信息,我又结合我开通的阿里云OSS后台,研究了一番所有功能发现,没有这方面的功能,倒是有个根据referer限制防盗链的,为了防止意外,我也是在请求头中加入了referer,值为该漫画网站的域名。
于是我又改造了下脚本,在章节地方加入了多线程。该本漫画,多个章节内容同时下载。刚开始还有点害怕,创建章节目录的地方还sleep一下,防止跑的太快等待随机的0-2秒钟,后来干脆sleep也注释掉了,直接狂奔,阿里云不愧是阿里云,OSS的访问速度嗖嗖的,不排除对方买了cdn加速服务,一秒几十张图片的速度下载着。
本来是打算晚上执行的,但是没忍住就把脚本跑了起来,毕竟自己创造的“孩子”总要拉出来溜溜。之所以想在半夜执行,就是怕跑着跑着把他的下行流量跑光,阿里云给他发欠费短信就暴露了,噗哈哈(鸡贼),爬取的过程中我也粗略的计算了下,20多万张图片应该有上20G吧,加入多线程的原因也是怕被发现,所以赶紧加速下载起来。
下载中看着控制台疯狂刷的日志,还是对之前的那个问题疑问着,难道漫画界更新有不成文的规定吗,每章节只更新3张图片?
全部下载完之后,发现有进30多G,随意打开一个漫画文件夹中,看了一篇,还真他妈好看,故事情节很带劲,咳咳。但是看完第一章,第二章,第三章怎么和第二章不连贯啊,之后的几个章节也是。这时想起来了那个VIP功能,是不是之后的所有章节都3张图片是预览的,之所以后端返回三张,有可能不是vip的缘故,完,这下没辙了。这爬下来也没法看啊!
于是再次分析,发现这个几口域名的根路径在浏览器打开竟然,和软件一样的界面,啧啧啧,最低成本的软件了,网页打包的,和我之前的那个助聊软件如出一辙,可惜我那个现在打开闪退了,也没再维护,现在主推助聊小程序和网页版了。
跑题了,说回这个网页打包的漫画软件,怪不得在软件里,漫画详情页顶部也显示让下载客户端,早发现不对劲了。既然网页打包的,还使用接口进行交互数据,这差不多是个前后端分离的项目。
伪造身份欺骗后台拿数据
得!既然涉及到VIP权限,那就先注册个账号看看吧,底部不是说的注册账号绑定手机送阅读币吗,看这阅读币能够阅读两章付费内容的了,那我要看看。你这网站到底有没有隐藏的内容,别再纸老虎般糊弄人,也没有章节的剩下内容。然而注册账号后,发现根本就没有绑定手机号的地方,就没这功能,妈的,这个线索又断了。
浏览器F12打开开发者工具,研究了一番接口参数数据,发现,登录后请求cookie中携带的参数引起了我的注意。
登录携带的cookie参数:
bzsoxmlusername=1qw21qw;bzsoxmluserid=65793;bzsoxmlgroupid=1;bzsoxmlrnd=7RyMS9Mb3Pmsd23ouNtV;bzsoxmlauth=5ec94540370f10520e7673a4ecb97d5a;ticket=7RyMS9Mb3Pmsd23ouNtV
直白的看得出分别是用户名、用户id、分组id后面的不知道啥意思了。如果userid递增的话。这网站用户还真不少,我是第6万多名了。
到这也始终没有突破口,于是猜想我的这个userid换成其他userid请求会有啥反应。于是携带上这个cookie,在postman中再次拿漫画章节详情试了试。关于id一般排在第一位的大多是管理员或者测试账号啥的,于是把bzsoxmluserid改成了1,找了个付费的章节,请求发现返回的真的不再是3条数据了,为了防止偏差,我把bzsoxmluserid改回我的id再次请求,发现返回3条数据,what?这就绕过了?额,的确就这样绕过了。
找到真相
于是我在浏览器中也是操作了一番,F12开发者工具Application-Storage-Cookies,直接修改bzsoxmluserid值为1。然后刷新网页,发现个人资料全变了,身份也真的是VIP,又测了其他userid发现,资料身份也会随着改变。真的是大的逻辑漏洞。
关于这个第一位id,之前绕过某网站后台也是通过这种方式绕过的(记一次攻破某网站拿到超级管理员权限的过程 )。所以对于这种递增的userid,排在前几位的不做处理,还是有点风险的,当前这不是主要的,其实也没关系。主要的是这网站逻辑的逻辑有巨大的漏洞,我猜想他们的逻辑是这样的:用户登录后,后端返回用户信息及其他参数给前端,前端放到cookie中,然后每次请求都携带着,后端获取到cookie信息后,只根据bzsoxmluserid查询数据库获取用户信息,来判断用户的权限角色等,如果该userid的账户是vip就返回所有的数据。对,肯定是这样的。
在发现userid是1可以返回所有数据后,立马改写了python脚本,加入了cookie参数,然后运行,看着控制台日志、数据库数据都正常的爬取中。
爬数据被抓
这时已经是晚上快21点了,脚本运行爬取了一会后看见控制台日志发现,不行了,从第二章之后又开始返回三条数据了,于是立马停掉脚本,postman再次请求发现已经不行了,卧槽这是咋回事,于是userid换成2、3、4,发现4是返回多条数据的,浏览器中发现是vip,并且还剩一个多月的时间。我猜想网站管理员肯定发现我爬取数据了,然后紧急把userid为1的账户撤掉了vip的角色。肯定是这样的。
接下来没有再运行脚本,我已经被监控了。然后对网站的各功能进行了检查,发现网站充值页面,写着客服在线时间是14点到凌晨12点,于是在第二天早晨又开始搞了,这次很顺利,userid用的4,这回数据量很大,上次半天就全部爬取完毕了,毕竟从第二章开始就只保存三条数据。这次他妈的984本漫画数据,爬取了整整一天,早晨6点40就开始搞起来了,中间出了一次差错,停了不到连分钟,又开始爬起来了,一直到晚上六点全部爬取脱库完毕。
数据披露
漫画主表数据一共984
条无差异
漫画章节目录表38507
条数据
漫画章节详情数据1903540
条数据
网站数据量可真不小。
关于网站会员,我也试了一些账号,比如比我userid大和小的id,发现会员身份的账号还是不少的,可见一斑,这违法网站靠会员收入还是非常赚钱的。
总结
这是一次典型的相信前端数据不验证的逻辑漏洞问题。哪怕他根据bzsoxmluserid和bzsoxmlusername联合验证身份也不会让我那么轻易的绕过权限。之前就看过相关的新闻,“某男子利用抓包软件修改请求接口参数,进行薅羊毛,给公司造成巨大损失”等等,这些都是后端不做安全验证而相信前端传过来数据的后果。所以我在开发工作中,是不会相信前端传过来的任何重要数据的。总是会在后端进行验证一遍,以减少不必要的损失,而且在服务层也会限制接口的请求频次,放置恶意用户对数据的爬取。
总之挺垃圾的,没什么技术含量。绕过了vip权限,也没啥成就感,网站挺垃圾的,漏洞也很低级。