입력 검증 및 표현 문제는 메타 문자, 대체 인코딩 및 숫자 표현 때문에 발생합니다. 보안 문제는 입력을 신뢰하기 때문에 발생합니다. 문제로는 "Buffer Overflows", "Cross-Site Scripting" 공격, "SQL Injection", 그 외 여러 가지가 있습니다.
Value Stack
컨텍스트의 EL 식을 평가할 수 있도록 합니다. 확인되지 않은 식을 Value Stack
과 비교하여 평가할 수 있게 하면 공격자가 액세스하여 시스템 변수를 수정하거나 임의의 코드를 실행할 수 있게 됩니다.
OgnlContext ctx = new OgnlContext();
String expression = request.getParameter("input");
Object expr = Ognl.parseExpression(expression);
Object value = Ognl.getValue(expr, ctx, root);
System.out.println("Value: " + value);
(#rt = @java.lang.Runtime@getRuntime(),#rt.exec("calc.exe"))
%{expr}
)을 사용합니다. 첫 번째 평가의 결과를 제어하는 공격자는 두 번째 OGNL 평가에서 평가될 식을 제어하고 임의의 OGNL 식을 삽입할 수 있습니다.redirectAction
결과는 매개 변수를 두 번 평가하는 것으로 알려져 있습니다. 이 경우 actionName
매개 변수의 강제 OGNL 식의 결과가 redirect
요청 매개 변수를 제공하여 공격자에 의해 제어될 수 있습니다.
...
<action name="index" class="com.acme.MyAction">
<result type="redirectAction">
<param name="actionName">${#parameters['redirect']}</param>
<param name="namespace">/foo</param>
</result>
</action>
...
%{#parameters['redirect']}
식을 평가하여 OGNL 식으로 평가될 사용자 제어 문자열을 반환하여 공격자가 임의의 OGNL 식을 평가할 수 있도록 합니다.execute()
외의 메서드가 노출될 수 있습니다. "동적 메서드 호출"이 활성화된 경우 !
(느낌표) 문자 또는 method:
접두사를 Action URL에 사용하여 Action의 모든 공개 메서드를 호출할 수 있습니다. Struts 2 버전 2.3.20
에서는 이전에 리플렉션을 기반으로 한 대체 메서드 호출 메커니즘이 OGNL을 대신 사용하도록 바뀌었는데 공격자는 이를 통해 대체 메서드 이름 대신 악성 OGNL 식을 제공할 수 있습니다.debug
요청 매개 변수를 사용하여 트리거할 수 있습니다.console
인 경우 개발자가 서버에서 임의의 OGNL 식을 평가할 수 있는 OGNL 평가 콘솔이 팝업으로 표시됩니다.command
인 경우 개발자는 요청 매개 변수 expression
을 사용하여 평가할 임의의 OGNL 식을 제출할 수 있습니다.xml
은 매개 변수, 컨텍스트, 세션 및 값 스택을 XML 문서로 덤프합니다.browser
는 매개 변수, 컨텍스트, 세션 및 값 스택을 검색 가능한 HTML 문서로 덤프합니다.dest
요청 매개 변수에서 구문 분석한 URL을 열도록 지시합니다.
...
DATA: str_dest TYPE c.
str_dest = request->get_form_field( 'dest' ).
response->redirect( str_dest ).
...
Example 1
의 코드가 브라우저를 “http://www.wilyhacker.com”으로 리디렉션합니다.dest
요청 매개 변수에서 읽어들인 URL을 열도록 지시합니다.
...
var params:Object = LoaderInfo(this.root.loaderInfo).parameters;
var strDest:String = String(params["dest"]);
host.updateLocation(strDest);
...
Example 1
의 코드가 브라우저를 “http://www.wilyhacker.com”으로 리디렉션합니다.dest
요청 매개 변수의 URL로 구성된 PageReference
개체를 반환합니다.
public PageReference pageAction() {
...
PageReference ref = ApexPages.currentPage();
Map<String,String> params = ref.getParameters();
return new PageReference(params.get('dest'));
}
Example 1
의 코드가 브라우저를 "http://www.wilyhacker.com"으로 리디렉션합니다.dest
요청 매개 변수에서 구문 분석한 URL을 열도록 지시합니다.
String redirect = Request["dest"];
Response.Redirect(redirect);
Example 1
의 코드가 브라우저를 “http://www.wilyhacker.com”으로 리디렉션합니다.dest
요청 매개 변수에서 구문 분석한 URL을 열도록 지시합니다.
...
final server = await HttpServer.bind(host, port);
await for (HttpRequest request in server) {
final response = request.response;
final headers = request.headers;
final strDest = headers.value('strDest');
response.headers.contentType = ContentType.text;
response.redirect(Uri.parse(strDest!));
await response.close();
}
...
Example 1
의 코드가 브라우저를 “http://www.wilyhacker.com”으로 리디렉션합니다.dest
요청 매개 변수에서 구문 분석한 URL을 열도록 지시합니다.
...
strDest := r.Form.Get("dest")
http.Redirect(w, r, strDest, http.StatusSeeOther)
...
Example 1
의 코드가 브라우저를 “http://www.wilyhacker.com”으로 리디렉션합니다.dest
요청 매개 변수에서 구문 분석한 URL을 열도록 지시합니다.
<end-state id="redirectView" view="externalRedirect:#{requestParameters.dest}" />
Example 1
의 코드가 브라우저를 “http://www.wilyhacker.com”으로 리디렉션합니다.dest
요청 매개 변수에서 읽어 들인 URL을 열도록 지시합니다.
...
strDest = form.dest.value;
window.open(strDest,"myresults");
...
Example 1
의 코드가 브라우저를 “http://www.wilyhacker.com”으로 리디렉션합니다.dest
요청 매개 변수에서 구문 분석한 URL을 열도록 사용자 브라우저에 지시합니다.
<%
...
$strDest = $_GET["dest"];
header("Location: " . $strDest);
...
%>
Example 1
의 코드가 브라우저를 “http://www.wilyhacker.com”으로 리디렉션합니다.dest
요청 매개 변수에서 구문 분석한 URL을 열도록 지시합니다.
...
-- Assume QUERY_STRING looks like dest=http://www.wilyhacker.com
dest := SUBSTR(OWA_UTIL.get_cgi_env('QUERY_STRING'), 6);
OWA_UTIL.redirect_url('dest');
...
Example 1
의 코드가 브라우저를 “http://www.wilyhacker.com”으로 리디렉션합니다.dest
요청 매개 변수에서 구문 분석한 URL을 열도록 지시합니다.
...
strDest = request.field("dest")
redirect(strDest)
...
Example 1
의 코드가 브라우저를 “http://www.wilyhacker.com”으로 리디렉션합니다.dest
요청 매개 변수에서 구문 분석한 URL을 열도록 지시합니다.
...
str_dest = req.params['dest']
...
res = Rack::Response.new
...
res.redirect("http://#{dest}")
...
Example 1
의 코드가 브라우저를 “http://www.wilyhacker.com”으로 리디렉션합니다.dest
요청 매개 변수에서 구문 분석한 URL을 열도록 지시합니다.
def myAction = Action { implicit request =>
...
request.getQueryString("dest") match {
case Some(location) => Redirect(location)
case None => Ok("No url found!")
}
...
}
Example 1
의 코드가 브라우저를 “http://www.wilyhacker.com”으로 리디렉션합니다.requestToLoad
가 원래 URL의 "dest" 매개 변수(있는 경우) 및 http://
스키마를 사용하는 원래 URL을 가리키도록 설정하고, 마지막으로 이 요청을 WKWebView 내에서 로드합니다.
...
let requestToLoad : String
...
func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {
...
if let urlComponents = NSURLComponents(URL: url, resolvingAgainstBaseURL: false) {
if let queryItems = urlComponents.queryItems as? [NSURLQueryItem]{
for queryItem in queryItems {
if queryItem.name == "dest" {
if let value = queryItem.value {
request = NSURLRequest(URL:NSURL(string:value))
requestToLoad = request
break
}
}
}
}
if requestToLoad == nil {
urlComponents.scheme = "http"
requestToLoad = NSURLRequest(URL:urlComponents.URL)
}
}
...
}
...
...
let webView : WKWebView
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
webView.loadRequest(appDelegate.requestToLoad)
...
Example 1
의 코드가 요청을 시도하고 WKWebView에서 “http://www.wilyhacker.com”을 로드합니다.dest
요청 매개 변수에서 구문 분석한 URL을 열도록 지시합니다.
...
strDest = Request.Form('dest')
HyperLink.NavigateTo strDest
...
Example 1
의 코드가 브라우저를 “http://www.wilyhacker.com”으로 리디렉션합니다.strncpy()
와 같은 범위 지정 함수도 잘못 사용되면 취약점을 일으킬 수 있습니다. 대부분의 buffer overflow의 원인은 메모리 조작과 데이터의 크기 또는 구성에 대한 가정 위반이 결합된 것입니다.memcpy()
호출은 cArray
의 할당된 경계 외부에서 메모리를 읽습니다. 여기에는 char
유형의 MAX
요소가 포함되지만 iArray
에는 int
유형의 MAX
요소가 포함됩니다.예제 2: 다음의 간단한 프로그램은 분석할 상수 바이트와 함께
void MemFuncs() {
char array1[MAX];
int array2[MAX];
memcpy(array2, array1, sizeof(array2));
}
memchr()
호출에서 신뢰할 수 없는 명령줄 인수를 검색 버퍼로 사용합니다.
int main(int argc, char** argv) {
char* ret = memchr(argv[0], 'x', MAX_PATH);
printf("%s\n", ret);
}
argv[0]
데이터를 상수 바이트까지 검색하여 argv[0]
의 부분 문자열을 인쇄하기 위한 것입니다. 그러나, 상수 바이트가 argv[0]
에 할당된 데이터보다 클 수도 있기 때문에 검색은 argv[0]
에 할당된 데이터를 넘어 계속됩니다. 이는 x
가 argv[0]
에 없을 경우입니다.strncpy()
와 같은 범위 지정 함수도 잘못 사용되면 취약점을 일으킬 수 있습니다. 대부분의 buffer overflow의 원인은 메모리 조작과 데이터의 크기 또는 구성에 대한 가정 위반이 결합된 것입니다.char
의 5 요소 배열을 연속적으로 역참조합니다.
char Read() {
char buf[5];
return 0
+ buf[0]
+ buf[1]
+ buf[2]
+ buf[3]
+ buf[4]
+ buf[5];
}
strncpy()
와 같은 범위 지정 함수도 잘못 사용되면 취약점을 일으킬 수 있습니다. 대부분의 buffer overflow의 원인은 메모리 조작과 데이터의 크기 또는 구성에 대한 가정 위반이 결합된 것입니다.getInputLength()
에서 읽은 신뢰할 수 없는 값이 대상 버퍼 output
의 크기보다 작은지 확인하여 경계 외부에서 buffer overflow를 읽는 것을 막습니다. 그러나 len
과 MAX
의 비교에 부호가 있으므로 len
이 음수인 경우 부호 없는 인수가 memcpy()
로 변환되면 매우 큰 양수가 됩니다.
void TypeConvert() {
char input[MAX];
char output[MAX];
fillBuffer(input);
int len = getInputLength();
if (len <= MAX) {
memcpy(output, input, len);
}
...
}
...
*Get the report that is to be deleted
r_name = request->get_form_field( 'report_name' ).
CONCATENATE `C:\\users\\reports\\` r_name INTO dsn.
DELETE DATASET dsn.
...
..\\..\\usr\\sap\\DVEBMGS00\\exe\\disp+work.exe
" 등의 파일 이름을 지정하면 응용 프로그램이 중요 파일을 삭제하게 되므로 SPS 시스템이 즉시 중단됩니다.
...
PARAMETERS: p_date TYPE string.
*Get the invoice file for the date provided
CALL FUNCTION 'FILE_GET_NAME'
EXPORTING
logical_filename = 'INVOICE'
parameter_1 = p_date
IMPORTING
file_name = v_file
EXCEPTIONS
file_not_found = 1
OTHERS = 2.
IF sy-subrc <> 0.
* Implement suitable error handling here
ENDIF.
OPEN DATASET v_file FOR INPUT IN TEXT MODE.
DO.
READ DATASET v_file INTO v_record.
IF SY-SUBRC NE 0.
EXIT.
ELSE.
WRITE: / v_record.
ENDIF.
ENDDO.
...
..\\..\\usr\\sap\\sys\\profile\\default.pfl
" 등의 문자열을 지정하면 응용 프로그램은 모든 기본 SAP 응용 프로그램 서버 매개 변수 설정을 노출시키고, 이는 더욱 치밀한 공격으로 이어질 수 있습니다.../../tomcat/conf/server.xml
" 등의 파일 이름을 제공하여 응용 프로그램이 자신의 구성 파일을 삭제하게 만들 가능성을 고려하지 않았습니다.예제 2: 다음 코드는 구성 파일의 입력을 사용하여 열 파일을 결정하고 "디버그" 콘솔 또는 로그 파일에 씁니다. 프로그램이 일정한 권한으로 실행되고 악의적인 사용자가 구성 파일을 변경할 수 있는 경우, 이 프로그램을 사용하여 시스템에서 확장명이
var params:Object = LoaderInfo(this.root.loaderInfo).parameters;
var rName:String = String(params["reportName"]);
var rFile:File = new File("/usr/local/apfr/reports/" + rName);
...
rFile.deleteFile();
.txt
인 파일을 읽을 수 있습니다.
var fs:FileStream = new FileStream();
fs.open(new File(String(configStream.readObject())+".txt"), FileMode.READ);
fs.readBytes(arr);
trace(arr);
public class MyController {
...
public PageRerference loadRes() {
PageReference ref = ApexPages.currentPage();
Map<String,String> params = ref.getParameters();
if (params.containsKey('resName')) {
if (params.containsKey('resPath')) {
return PageReference.forResource(params.get('resName'), params.get('resPath'));
}
}
return null;
}
}
..\\..\\Windows\\System32\\krnl386.exe
" 등의 파일 이름을 제공하여 응용 프로그램이 중요한 Windows 시스템 파일을 삭제하게 만들 가능성을 고려하지 않았습니다.예제 2: 다음 코드는 구성 파일의 입력을 사용하여 열 파일을 결정하고 사용자에게 돌려 보냅니다. 프로그램이 충분한 권한으로 실행되고 악의적인 사용자가 구성 파일을 변경할 수 있는 경우, 이 프로그램을 사용하여 시스템에서 확장명이 ".txt"인 파일을 읽을 수 있습니다.
String rName = Request.Item("reportName");
...
File.delete("C:\\users\\reports\\" + rName);
sr = new StreamReader(resmngr.GetString("sub")+".txt");
while ((line = sr.ReadLine()) != null) {
Console.WriteLine(line);
}
../../apache/conf/httpd.conf
" 등의 파일 이름을 제공하여 응용 프로그램이 지정한 구성 파일을 삭제하게 만들 가능성을 고려하지 않았습니다.예제 2: 다음 코드는 명령줄의 입력을 사용하여 열 파일을 결정하고 사용자에게 돌려 보냅니다. 프로그램이 충분한 권한으로 실행되고 악의적인 사용자가 파일에 대한 소프트 링크를 만들게 되면 프로그램을 이용하여 시스템의 모든 파일의 첫 부분을 읽을 수 있습니다.
char* rName = getenv("reportName");
...
unlink(rName);
ifstream ifs(argv[0]);
string s;
ifs >> s;
cout << s;
...
EXEC CICS
WEB READ
FORMFIELD(FILE)
VALUE(FILENAME)
...
END-EXEC.
EXEC CICS
READ
FILE(FILENAME)
INTO(RECORD)
RIDFLD(ACCTNO)
UPDATE
...
END-EXEC.
...
..\\..\\Windows\\System32\\krnl386.exe
" 등의 파일 이름을 제공하여 응용 프로그램이 중요한 Windows 시스템 파일을 삭제하게 만들 가능성을 고려하지 않았습니다.
<cffile action = "delete"
file = "C:\\users\\reports\\#Form.reportName#">
final server = await HttpServer.bind('localhost', 18081);
server.listen((request) async {
final headers = request.headers;
final path = headers.value('path');
File(path!).delete();
}
Example 1
에서는 파일에 대한 삭제 기능을 수행하기 전에 headers.value('path')
의 유효성을 검사하지 않습니다.../../tomcat/conf/server.xml
" 등의 파일 이름을 제공하여 응용 프로그램이 자신의 구성 파일을 삭제하게 만들 가능성을 고려하지 않았습니다.예제 2: 다음 코드는 구성 파일의 입력을 사용하여 열 파일을 결정하고 사용자에게 돌려 보냅니다. 프로그램이 일정한 권한으로 실행되고 악의적인 사용자가 구성 파일을 변경할 수 있는 경우, 이 프로그램을 사용하여 시스템에서 확장명이
rName := "/usr/local/apfr/reports/" + req.FormValue("fName")
rFile, err := os.OpenFile(rName, os.O_RDWR|os.O_CREATE, 0755)
defer os.Remove(rName);
defer rFile.Close()
...
.txt
인 파일을 읽을 수 있습니다.
...
config := ReadConfigFile()
filename := config.fName + ".txt";
data, err := ioutil.ReadFile(filename)
...
fmt.Println(string(data))
../../tomcat/conf/server.xml
" 등의 파일 이름을 제공하여 응용 프로그램이 자신의 구성 파일을 삭제하게 만들 가능성을 고려하지 않았습니다.예제 2: 다음 코드는 구성 파일의 입력을 사용하여 열 파일을 결정하고 사용자에게 돌려 보냅니다. 프로그램이 일정한 권한으로 실행되고 악의적인 사용자가 구성 파일을 변경할 수 있는 경우, 이 프로그램을 사용하여 시스템에서 확장명이
String rName = request.getParameter("reportName");
File rFile = new File("/usr/local/apfr/reports/" + rName);
...
rFile.delete();
.txt
인 파일을 읽을 수 있습니다.
fis = new FileInputStream(cfg.getProperty("sub")+".txt");
amt = fis.read(arr);
out.println(arr);
Example 1
을 Android 플랫폼에 맞게 조정합니다.
...
String rName = this.getIntent().getExtras().getString("reportName");
File rFile = getBaseContext().getFileStreamPath(rName);
...
rFile.delete();
...
../../tomcat/conf/server.xml
" 등의 파일 이름을 제공하여 응용 프로그램이 자신의 구성 파일을 삭제하게 만들 가능성을 고려하지 않았습니다.예제 2: 다음 코드는 로컬 저장소의 입력을 사용하여 열 파일을 결정하고 사용자에게 돌려보냅니다. 악의적인 사용자가 로컬 저장소의 내용을 변경할 수 있는 경우, 이 프로그램을 사용하여 시스템에서 확장명이
...
var reportNameParam = "reportName=";
var reportIndex = document.indexOf(reportNameParam);
if (reportIndex < 0) return;
var rName = document.URL.substring(reportIndex+reportNameParam.length);
window.requestFileSystem(window.TEMPORARY, 1024*1024, function(fs) {
fs.root.getFile('/usr/local/apfr/reports/' + rName, {create: false}, function(fileEntry) {
fileEntry.remove(function() {
console.log('File removed.');
}, errorHandler);
}, errorHandler);
}, errorHandler);
.txt
인 파일을 읽을 수 있습니다.
...
var filename = localStorage.sub + '.txt';
function oninit(fs) {
fs.root.getFile(filename, {}, function(fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(e) {
var txtArea = document.createElement('textarea');
txtArea.value = this.result;
document.body.appendChild(txtArea);
};
reader.readAsText(file);
}, errorHandler);
}, errorHandler);
}
window.requestFileSystem(window.TEMPORARY, 1024*1024, oninit, errorHandler);
...
../../tomcat/conf/server.xml
" 등의 파일 이름을 제공하여 응용 프로그램이 자신의 구성 파일을 삭제하게 만들 가능성을 고려하지 않았습니다.예제 2: 다음 코드는 구성 파일의 입력을 사용하여 열 파일을 결정하고 사용자에게 돌려 보냅니다. 프로그램이 일정한 권한으로 실행되고 악의적인 사용자가 구성 파일을 변경할 수 있는 경우, 이 프로그램을 사용하여 시스템에서 확장명이
val rName: String = request.getParameter("reportName")
val rFile = File("/usr/local/apfr/reports/$rName")
...
rFile.delete()
.txt
인 파일을 읽을 수 있습니다.
fis = FileInputStream(cfg.getProperty("sub").toString() + ".txt")
amt = fis.read(arr)
out.println(arr)
Example 1
을 Android 플랫폼에 맞게 조정합니다.
...
val rName: String = getIntent().getExtras().getString("reportName")
val rFile: File = getBaseContext().getFileStreamPath(rName)
...
rFile.delete()
...
- (NSData*) testFileManager {
NSString *rootfolder = @"/Documents/";
NSString *filePath = [rootfolder stringByAppendingString:[fileName text]];
NSFileManager *fm = [NSFileManager defaultManager];
return [fm contentsAtPath:filePath];
}
../../tomcat/conf/server.xml
" 등의 파일 이름을 제공하여 응용 프로그램이 자신의 구성 파일을 삭제하게 만들 가능성을 고려하지 않았습니다.예제 2: 다음 코드는 구성 파일의 입력을 사용하여 열 파일을 결정하고 사용자에게 돌려 보냅니다. 프로그램이 일정한 권한으로 실행되고 악의적인 사용자가 구성 파일을 변경할 수 있는 경우, 이 프로그램을 사용하여 시스템에서 확장명이
$rName = $_GET['reportName'];
$rFile = fopen("/usr/local/apfr/reports/" . rName,"a+");
...
unlink($rFile);
.txt
인 파일을 읽을 수 있습니다.
...
$filename = $CONFIG_TXT['sub'] . ".txt";
$handle = fopen($filename,"r");
$amt = fread($handle, filesize($filename));
echo $amt;
...
../../tomcat/conf/server.xml
" 등의 파일 이름을 제공하여 응용 프로그램이 자신의 구성 파일을 삭제하게 만들 가능성을 고려하지 않았습니다.예제 2: 다음 코드는 구성 파일의 입력을 사용하여 열 파일을 결정하고 사용자에게 돌려 보냅니다. 프로그램이 일정한 권한으로 실행되고 악의적인 사용자가 구성 파일을 변경할 수 있는 경우, 이 프로그램을 사용하여 시스템에서 확장명이
rName = req.field('reportName')
rFile = os.open("/usr/local/apfr/reports/" + rName)
...
os.unlink(rFile);
.txt
인 파일을 읽을 수 있습니다.
...
filename = CONFIG_TXT['sub'] + ".txt";
handle = os.open(filename)
print handle
...
../../tomcat/conf/server.xml
" 등의 파일 이름을 제공하여 응용 프로그램이 자신의 구성 파일을 삭제하게 만들 가능성을 고려하지 않았습니다.예제 2: 다음 코드는 구성 파일의 입력을 사용하여 열 파일을 결정하고 사용자에게 돌려 보냅니다. 프로그램이 일정한 권한으로 실행되고 악의적인 사용자가 구성 파일을 변경할 수 있는 경우, 이 프로그램을 사용하여 시스템에서 확장명이
rName = req['reportName']
File.delete("/usr/local/apfr/reports/#{rName}")
.txt
인 파일을 읽을 수 있습니다.
...
fis = File.new("#{cfg.getProperty("sub")}.txt")
amt = fis.read
puts amt
../../tomcat/conf/server.xml
" 등의 파일 이름을 제공하여 응용 프로그램이 자신의 구성 파일을 삭제하게 만들 가능성을 고려하지 않았습니다.예제 2: 다음 코드는 구성 파일의 입력을 사용하여 열 파일을 결정하고 사용자에게 돌려 보냅니다. 프로그램이 일정한 권한으로 실행되고 악의적인 사용자가 구성 파일을 변경할 수 있는 경우, 이 프로그램을 사용하여 시스템에서 확장명이
def readFile(reportName: String) = Action { request =>
val rFile = new File("/usr/local/apfr/reports/" + reportName)
...
rFile.delete()
}
.txt
인 파일을 읽을 수 있습니다.
val fis = new FileInputStream(cfg.getProperty("sub")+".txt")
val amt = fis.read(arr)
out.println(arr)
func testFileManager() -> NSData {
let filePath : String = "/Documents/\(fileName.text)"
let fm : NSFileManager = NSFileManager.defaultManager()
return fm.contentsAtPath(filePath)
}
..\conf\server.xml
" 등의 파일 이름을 제공하여 응용 프로그램이 자신의 구성 파일을 삭제하게 만들 가능성을 고려하지 않았습니다.예제 2: 다음 코드는 구성 파일의 입력을 사용하여 열 파일을 결정하고 사용자에게 돌려 보냅니다. 프로그램이 일정한 권한으로 실행되고 악의적인 사용자가 구성 파일을 변경할 수 있는 경우, 이 프로그램을 사용하여 시스템에서 확장명이
Dim rName As String
Dim fso As New FileSystemObject
Dim rFile as File
Set rName = Request.Form("reportName")
Set rFile = fso.GetFile("C:\reports\" & rName)
...
fso.DeleteFile("C:\reports\" & rName)
...
.txt
인 파일을 읽을 수 있습니다.
Dim fileName As String
Dim tsContent As String
Dim ts As TextStream
Dim fso As New FileSystemObject
fileName = GetPrivateProfileString("MyApp", "sub", _
"", value, Len(value), _
App.Path & "\" & "Config.ini")
...
Set ts = fso.OpenTextFile(fileName,1)
tsContent = ts.ReadAll
Response.Write tsContent
...
Path.Combine
은 여러 파일 경로를 인수로 사용합니다. 일반적으로 파일에 대한 read()
또는 write()
호출 후에 여러 파일 경로를 연결하여 하나의 전체 경로를 가져옵니다. 첫 번째 또는 나머지 매개 변수가 절대 경로인지 여부에 따라 서로 다른 여러 시나리오가 설명서에 설명되어 있습니다. 두 번째 또는 나머지 매개 변수가 절대 경로인 경우 Path.Combine()
은 해당 절대 경로를 반환합니다. 이전 매개 변수는 무시됩니다. 이 경우 다음 예제와 유사한 코드가 있는 응용 프로그램에서 심각한 영향이 발생합니다.
// Called with user-controlled data
public static bytes[] getFile(String filename)
{
String imageDir = "\\FILESHARE\images\";
filepath = Path.Combine(imageDir, filename);
return File.ReadAllBytes(filepath);
}
C:\\inetpub\wwwroot\web.config
)를 제공하여 응용 프로그램이 반환하는 파일을 제어할 수 있습니다.
...
" Add Binary File to
CALL METHOD lr_abap_zip->add
EXPORTING
name = p_ifile
content = lv_bufferx.
" Read Binary File to
CALL METHOD lr_abap_zip->get
EXPORTING
name = p_ifile
IMPORTING
content = lv_bufferx2.
...
Example 1
에서는 이 항목 내의 데이터에 대한 읽기/쓰기 기능을 수행하기 전에 p_ifile
검증을 수행하지 않습니다. ZIP 파일이 Unix 기반 컴퓨터의 “/tmp/
” 디렉터리에 원래 배치되었고 ZIP 항목이 “../etc/hosts
”이며 응용 프로그램이 필요한 권한으로 실행되는 경우 이 파일이 시스템 hosts
파일을 덮어씁니다. 그러면 공격자는 컴퓨터의 트래픽을 공격자 컴퓨터로 다시 보내는 등 원하는 모든 위치로 전송할 수 있습니다.
public static void UnzipFile(ZipArchive archive, string destDirectory)
{
foreach (var entry in archive.Entries)
{
string file = entry.FullName;
if (!string.IsNullOrEmpty(file))
{
string destFileName = Path.Combine(destDirectory, file);
entry.ExtractToFile(destFileName, true);
}
}
}
Example 1
에서는 이 항목 내의 데이터에 대한 읽기/쓰기 작업을 수행하기 전에 entry.FullName
검증을 수행하지 않습니다. ZIP 파일이 원래 “C:\TEMP
” 디렉터리에 위치하고 ZIP 항목 이름에 “..\
세그먼트”가 포함되었으며 응용 프로그램이 필요한 권한으로 실행된 경우 시스템 파일을 임의로 덮어쓸 수 있습니다.
func Unzip(src string, dest string) ([]string, error) {
var filenames []string
r, err := zip.OpenReader(src)
if err != nil {
return filenames, err
}
defer r.Close()
for _, f := range r.File {
// Store filename/path for returning and using later on
fpath := filepath.Join(dest, f.Name)
filenames = append(filenames, fpath)
if f.FileInfo().IsDir() {
// Make Folder
os.MkdirAll(fpath, os.ModePerm)
continue
}
// Make File
if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
return filenames, err
}
outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return filenames, err
}
rc, err := f.Open()
if err != nil {
return filenames, err
}
_, err = io.Copy(outFile, rc)
// Close the file without defer to close before next iteration of loop
outFile.Close()
rc.Close()
if err != nil {
return filenames, err
}
}
return filenames, nil
}
Example 1
에서는 이 항목 내의 데이터에 대한 읽기/쓰기 기능을 수행하기 전에 f.Name
검증을 수행하지 않습니다. ZIP 파일이 Unix 기반 컴퓨터의 “/tmp/
” 디렉터리에 원래 배치되었고 ZIP 항목이 “../etc/hosts
”이며 응용 프로그램이 필요한 권한으로 실행되는 경우 이 파일이 시스템 hosts
파일을 덮어씁니다. 그러면 공격자는 컴퓨터의 트래픽을 공격자 컴퓨터로 다시 보내는 등 원하는 모든 위치로 전송할 수 있습니다.
private static final int BUFSIZE = 512;
private static final int TOOBIG = 0x640000;
...
public final void unzip(String filename) throws IOException {
FileInputStream fis = new FileInputStream(filename);
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(fis));
ZipEntry zipEntry = null;
int numOfEntries = 0;
long total = 0;
try {
while ((zipEntry = zis.getNextEntry()) != null) {
byte data[] = new byte[BUFSIZE];
int count = 0;
String outFileName = zipEntry.getName();
if (zipEntry.isDirectory()){
new File(outFileName).mkdir(); //create the new directory
continue;
}
FileOutputStream outFile = new FileOutputStream(outFileName);
BufferedOutputStream dest = new BufferedOutputStream(outFile, BUFSIZE);
//read data from Zip, but do not read huge entries
while (total + BUFSIZE <= TOOBIG && (count = zis.read(data, 0, BUFSIZE)) != -1) {
dest.write(data, 0, count);
total += count;
}
...
}
} finally{
zis.close();
}
}
...
Example 1
에서는 이 항목 내의 데이터에 대한 읽기/쓰기 기능을 수행하기 전에 zipEntry.getName()
검증을 수행하지 않습니다. ZIP 파일이 Unix 기반 컴퓨터의 “/tmp/
” 디렉터리에 원래 배치되었고 ZIP 항목이 “../etc/hosts
”이며 응용 프로그램이 필요한 권한으로 실행되는 경우 이 파일이 시스템 hosts
파일을 덮어씁니다. 그러면 공격자는 컴퓨터의 트래픽을 공격자 컴퓨터로 다시 보내는 등 원하는 모든 위치로 전송할 수 있습니다.
var unzipper = require('unzipper');
var fs = require('fs');
var untrusted_zip = getZipFromRequest();
fs.createReadStream(zipPath).pipe(unzipper.Extract({ path: 'out' }));
ZZArchive* archive = [ZZArchive archiveWithURL:[NSURL fileURLWithPath: zipPath] error:&error];
for (ZZArchiveEntry* entry in archive.entries) {
NSString *fullPath = [NSString stringWithFormat: @"%@/%@", destPath, [entry fileName]];
[[entry newDataWithError:nil] writeToFile:newFullPath atomically:YES];
}
Example 1
에서는 이 항목 내의 데이터에 대한 읽기/쓰기 기능을 수행하기 전에 entry.fileName
검증을 수행하지 않습니다. ZIP 파일이 iOS 응용 프로그램의 “Documents/hot_patches
” 디렉터리에 원래 배치되었고 ZIP 항목이 “../js/page.js
”인 경우 page.js
파일을 덮어씁니다. 이로 인해 공격자는 코드 실행을 야기할 수 있는 악성 코드를 삽입할 수 있게 됩니다.
...
$zip = new ZipArchive();
$zip->open("userdefined.zip", ZipArchive::RDONLY);
$zpm = $zip->getNameIndex(0);
$zip->extractTo($zpm);
...
Example 1
에서는 이 항목 내의 데이터에 대한 읽기/쓰기 기능을 수행하기 전에 f.Name
검증을 수행하지 않습니다. ZIP 파일이 Unix 기반 컴퓨터의 “/tmp/
” 디렉터리에 있고 ZIP 항목이 “../etc/hosts
”이며 응용 프로그램이 필요한 권한으로 실행되는 경우 이 파일이 시스템 hosts
파일을 덮어씁니다. 그러면 공격자는 컴퓨터의 트래픽을 공격자 컴퓨터로 다시 보내는 등 원하는 모든 위치로 전송할 수 있습니다.
import zipfile
import tarfile
def unzip(archive_name):
zf = zipfile.ZipFile(archive_name)
zf.extractall(".")
zf.close()
def untar(archive_name):
tf = tarfile.TarFile(archive_name)
tf.extractall(".")
tf.close()
예제 2: 다음 예제에서는 ZIP 파일에서 파일을 추출한 다음 안전하지 않은 방식으로 파일을 디스크에 씁니다.
import better.files._
...
val zipPath: File = getUntrustedZip()
val destinationPath = file"out/dest"
zipPath.unzipTo(destination = destinationPath)
import better.files._
...
val zipPath: File = getUntrustedZip()
val destinationPath = file"out/dest"
zipPath.newZipInputStream.mapEntries( (entry : ZipEntry) => {
entry.extractTo(destinationPath, new FileInputStream(entry.getName))
})
Example 2
에서는 이 항목 내의 데이터에 대한 읽기/쓰기 기능을 수행하기 전에 entry.getName
검증을 수행하지 않습니다. ZIP 파일이 Unix 기반 컴퓨터의 “/tmp/
” 디렉터리에 원래 배치되었고 ZIP 항목이 “../etc/hosts
”이며 응용 프로그램이 필요한 권한으로 실행되는 경우 이 파일이 시스템 hosts
파일을 덮어씁니다. 그러면 공격자는 컴퓨터의 트래픽을 공격자 컴퓨터로 다시 보내는 등 원하는 모든 위치로 전송할 수 있습니다.
let archive = try ZZArchive.init(url: URL(fileURLWithPath: zipPath))
for entry in archive.entries {
let fullPath = URL(fileURLWithPath: destPath + "/" + entry.fileName)
try entry.newData().write(to: fullPath)
}
Example 1
에서는 이 항목 내의 데이터에 대한 읽기/쓰기 기능을 수행하기 전에 entry.fileName
검증을 수행하지 않습니다. ZIP 파일이 iOS 응용 프로그램의 “Documents/hot_patches
” 디렉터리에 원래 배치되었고 ZIP 항목이 “../js/page.js
”인 경우 page.js
파일을 덮어씁니다. 이로 인해 공격자는 코드 실행을 야기할 수 있는 악성 코드를 삽입할 수 있게 됩니다.varName
에 대한 악성 값을 공급하면 SetVariable()
에 대한 호출이 #first#
등 모든 임의 변수를 덮어쓸 수 있습니다. 이 경우, JavaScript를 포함하는 악성 값이 #first#
를 덮어쓰면 프로그램이 Cross-Site Scripting에 취약해집니다.
<cfset first = "User">
<cfscript>
SetVariable(url.varName, url.varValue);
</cfscript>
<cfoutput>
#first#
</cfoutput>
str
에 대한 악성 값을 공급하면 parse_str()
에 대한 호출이 first
를 포함하여 현재 범위의 모든 임의 변수를 덮어쓸 수 있습니다. 이 경우, JavaScript를 포함하는 악성 값이 first
를 덮어쓰면 프로그램이 Cross-Site Scripting에 취약해집니다.
<?php
$first="User";
...
$str = $_SERVER['QUERY_STRING'];
parse_str($str);
echo $first;
?>
str
에 대한 악성 값을 공급하면 mb_parse_str()
에 대한 호출이 first
를 포함하여 모든 임의 변수를 덮어쓸 수 있습니다. 이 경우, JavaScript를 포함하는 악성 값이 first
를 덮어쓰면 프로그램이 Cross-Site Scripting에 취약해집니다.
<?php
$first="User";
...
$str = $_SERVER['QUERY_STRING'];
mb_parse_str($str);
echo $first;
?>
NSPredicate
를 생성하면 공격자는 해당 문의 의미를 수정할 수 있습니다.NSPredicate
인스턴스는 CoreData
영구적 저장소 시스템, 배열 및 사전과 같은 소스에서 컬렉션을 가져오거나 필터링하는 방법을 지정합니다. 해당 쿼리 언어는 컬렉션을 검색하는 논리적 조건을 정의할 수 있도록 SQL
과 유사한 표현 언어를 제공합니다.NSPredicate
가 인증 요소로 사용되는 방법을 보여줍니다. 사용자가 임의의 PIN 값을 제공할 수 있으므로 와일드카드 문자(*
)를 사용하여 PIN 보호를 우회할 수 있습니다.
NSString *pin = [self getPinFromUser];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"pin LIKE %@", pin];
NSPredicate
를 생성하면 공격자는 해당 문의 의미를 수정할 수 있습니다.NSPredicate
인스턴스는 CoreData
영구적 저장소 시스템, 배열 및 사전과 같은 소스에서 컬렉션을 가져오거나 필터링하는 방법을 지정합니다. 해당 쿼리 언어는 컬렉션을 검색하는 논리적 조건을 정의할 수 있도록 SQL
과 유사한 표현 언어를 제공합니다.NSPredicate
가 인증 요소로 사용되는 방법을 보여줍니다. 사용자가 임의의 PIN 값을 제공할 수 있으므로 와일드카드 문자(*
)를 사용하여 PIN 보호를 우회할 수 있습니다.
let pin = getPinFromUser();
let predicate = NSPredicate(format: "pin LIKE '\(pin)'", argumentArray: nil)
...
tid = request->get_form_field( 'tid' ).
CALL TRANSACTION tid USING bdcdata MODE 'N'
MESSAGES INTO messtab.
...
APPHOME
을 사용하고 그런 다음 지정된 디렉터리에서 상대 경로를 사용하여 기본 라이브러리를 로드합니다.
...
string lib = ConfigurationManager.AppSettings["APPHOME"];
Environment.ExitCode = AppDomain.CurrentDomain.ExecuteAssembly(lib);
...
APPHOME
을 LIBNAME
의 악성 버전이 들어 있는 다른 경로를 가리키도록 수정하기 때문에 공격자가 라이브러리 또는 실행 파일을 로드하고 응용 프로그램에 대한 높은 권한으로 임의의 코드를 실행할 수도 있습니다. 프로그램이 환경에서 읽은 값을 확인하지 않기 때문에, 공격자가 시스템 속성 APPHOME
의 값을 제어할 수 있는 경우 응용 프로그램을 조작하여 악성 코드를 실행하게 하고 시스템을 제어할 수 있습니다.
...
RegQueryValueEx(hkey, "APPHOME",
0, 0, (BYTE*)home, &size);
char* lib=(char*)malloc(strlen(home)+strlen(INITLIB));
if (lib) {
strcpy(lib,home);
strcat(lib,INITCMD);
LoadLibrary(lib);
}
...
INITLIB
의 악성 버전이 들어 있는 다른 경로를 지정하는 방식으로 높은 응용 프로그램 권한으로 이 라이브러리에서 코드를 실행합니다. 프로그램이 환경에서 읽은 값을 확인하지 않기 때문에 공격자가 APPHOME
의 값을 제어하게 되면 응용 프로그램이 악성 코드를 실행하게 만들 수 있습니다.liberty.dll
이라는 라이브러리를 사용합니다.
LoadLibrary("liberty.dll");
liberty.dll
l의 절대 경로를 지정하지 않습니다. 공격자가 검색 순서에서 원하는 파일보다 앞쪽에 liberty.dll
이라는 악성 라이브러리를 배치하고 웹 서버 환경이 아닌 자신의 환경에서 프로그램을 실행할 방법을 찾게 되면 응용 프로그램은 신뢰할 수 있는 라이브러리 대신 악성 라이브러리를 로드합니다. 이런 종류의 응용 프로그램은 높은 권한으로 실행되기 때문에 공격자의 liberty.dll
의 내용도 높은 권한으로 실행되고 공격자가 시스템을 완전히 장악할 수 있습니다.LoadLibrary()
가 사용하는 검색 순서 때문에 발생합니다. Windows 최신 버전까지 그래왔듯이 시스템 디렉터리보다 현재 디렉터리를 먼저 검색하면 공격자가 프로그램을 로컬로 수행할 수 있어도 이런 종류의 공격은 하찮은 것이 됩니다. 검색 순서는 운영 체제 버전에 따라 결정되고 최신 운영 체제에서 다음 레지스트리 키의 값에 따라 제어됩니다.
HKLM\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode
LoadLibrary()
는 다음과 같이 동작합니다.SafeDllSearchMode
가 1인 경우 검색 순서는 다음과 같습니다.PATH
환경 변수에 나열된 디렉터리.SafeDllSearchMode
가 0인 경우 검색 순서는 다음과 같습니다.PATH
환경 변수에 나열된 디렉터리.
...
ACCEPT PROGNAME.
EXEC CICS
LINK PROGRAM(PROGNAME)
COMMAREA(COMA)
LENGTH(LENA)
DATALENGTH(LENI)
SYSID('CONX')
END-EXEC.
...
APPHOME
을 사용하여 코드가 설치되는 디렉터리를 결정한 다음 특정 디렉터리 기준 상대 경로를 사용하여 네이티브 라이브러리를 로드합니다.
...
String home = System.getProperty("APPHOME");
String lib = home + LIBNAME;
java.lang.Runtime.getRuntime().load(lib);
...
APPHOME
을 LIBNAME
의 악성 버전이 들어 있는 다른 경로를 가리키도록 수정하기 때문에 공격자가 라이브러리를 로드하고 응용 프로그램에 대한 높은 권한으로 임의의 코드를 실행할 수도 있습니다. 프로그램이 환경에서 읽은 값을 확인하지 않기 때문에, 공격자가 시스템 속성 APPHOME
의 값을 제어할 수 있는 경우 응용 프로그램을 조작하여 악성 코드를 실행하게 하고 시스템을 제어할 수 있습니다. System.loadLibrary()
를 사용하여 보통 표준 시스템 디렉터리에 있는 library.dll
이라는 기본 라이브러리에서 코드를 로드합니다.
...
System.loadLibrary("library.dll");
...
System.loadLibrary()
가 로드할 라이브러리에 대해 경로가 아닌 라이브러리 이름을 받는다는 점입니다. Java 1.4.2 API 설명서에 따르면 이 함수는 다음과 같이 동작합니다[1]:library.dll
의 악성 복사본을 배치하게 되면 응용 프로그램은 의도한 파일이 아닌 악성 복사본을 로드합니다. 응용 프로그램은 그 속성 때문에 높은 권한으로 실행됩니다. 즉, 공격자의 library.dll
의 내용이 높은 권한으로 실행되어 공격자에게 시스템의 완전한 제어권을 넘겨줄 수 있습니다.Express
의 현재 문서화되지 않은 "기능" 을 사용하여 동적으로 라이브러리 파일을 로드합니다. 그런 다음 Node.js
는 계속해서 이 라이브러리([1])가 포함된 파일 또는 디렉터리에 대한 일반 라이브러리 로드 경로를 검색합니다.
var express = require('express');
var app = express();
app.get('/', function(req, res, next) {
res.render('tutorial/' + req.params.page);
});
Express
에서 Response.render()
로 전달된 페이지는 이전에 알 수 없을 때 확장의 라이브러리를 로드합니다. 이는 잘 알려진 템플릿 엔진인 pug
라이브러리 로드를 의미하기 때문에 일반적으로 "foo.pug"와 같은 입력에 대해 문제가 되지 않습니다. 하지만 공격자가 페이지와 확장을 제어할 수 있는 경우 공격자는 Node.js
모듈 로드 경로 내의 모든 라이브러리를 로드하도록 선택할 수 있습니다. 프로그램이 URL 매개 변수에서 수신한 정보를 검증하지 않기 때문에 공격자는 응용 프로그램을 조작하여 악성 코드를 실행하게 하고 시스템을 제어할 수 있습니다.APPHOME
을 사용하여 코드가 설치되는 디렉터리를 결정한 다음 특정 디렉터리 기준 상대 경로를 사용하여 네이티브 라이브러리를 로드합니다.
...
$home = getenv("APPHOME");
$lib = $home + $LIBNAME;
dl($lib);
...
APPHOME
을 LIBNAME
의 악성 버전이 들어 있는 다른 경로를 가리키도록 수정하기 때문에 공격자가 라이브러리를 로드하고 응용 프로그램에 대한 높은 권한으로 임의의 코드를 실행할 수도 있습니다. 프로그램이 환경에서 읽은 값을 확인하지 않기 때문에, 공격자가 시스템 속성 APPHOME
의 값을 제어할 수 있는 경우 응용 프로그램을 조작하여 악성 코드를 실행하게 하고 시스템을 제어할 수 있습니다.dl()
을 사용하여 sockets.dll
이라는 이름의 라이브러리에서 코드를 로드하며, 이는 설치나 구성에 따라 다양한 위치에서 로드될 수 있습니다.
...
dl("sockets");
...
dl()
가 로드할 라이브러리에 대해 경로가 아닌 라이브러리 이름을 받는다는 점입니다.sockets.dll
의 악성 복사본을 배치하게 되면 응용 프로그램은 의도한 파일이 아닌 악성 복사본을 로드합니다. 응용 프로그램은 그 속성 때문에 높은 권한으로 실행됩니다. 즉, 공격자의 sockets.dll
의 내용이 높은 권한으로 실행되어 공격자에게 시스템의 완전한 제어권을 넘겨줄 수 있습니다.Kernel.system()
을 실행하여 보통 표준 시스템 디렉터리에 있는 program.exe
라는 실행 파일을 실행합니다.
...
system("program.exe")
...
Kernel.system()
은 셸을 통해 무언가를 실행합니다. 공격자가 환경 변수 RUBYSHELL
또는 COMSPEC
을 조작할 수 있다면 Kernel.system()
에 지정되는 명령으로 호출되는 악성 실행 파일을 가리킬 수 있습니다. 응용 프로그램은 그 속성 때문에 시스템 작업을 수행하는 데 필요한 권한으로 실행됩니다. 즉, 공격자의 program.exe
는 이 권한으로 실행되어 공격자에게 시스템의 완전한 제어권을 넘겨줄 수 있습니다.Kernel.system()
호출을 실행하기 전에 환경이 정리되지 않는다는 점입니다. 공격자가 $PATH
변수를 수정하여 program.exe
라는 악성 이진 파일을 가리키도록 하고 자신의 환경에서 프로그램을 실행하면 원하는 파일 대신 악성 이진 파일이 로드됩니다. 응용 프로그램은 그 속성 때문에 시스템 작업을 수행하는 데 필요한 권한으로 실행됩니다. 즉, 공격자의 program.exe
는 이 권한으로 실행되어 공격자에게 시스템의 완전한 제어권을 넘겨줄 수 있습니다.InvokerServlet
클래스를 사용하면 공격자가 서버에서 모든 클래스를 호출할 수 있습니다.InvokerServlet
클래스는 서버의 가상 시스템에 사용할 수 있는 모든 클래스를 호출하는 데 사용할 수 있습니다. 정규화된 클래스 이름을 추측하여 공격자가 Servlet 클래스뿐만 아니라 POJO 클래스 또는 JVM에 사용 가능한 기타 클래스를 로드할 수 있습니다.
@GetMapping("/prompt_injection")
String generation(String userInput1, ...) {
return this.clientBuilder.build().prompt()
.system(userInput1)
.user(...)
.call()
.content();
}
client = new Anthropic();
# Simulated attacker's input attempting to inject a malicious system prompt
attacker_input = ...
response = client.messages.create(
model = "claude-3-5-sonnet-20240620",
max_tokens=2048,
system = attacker_input,
messages = [
{"role": "user", "content": "Analyze this dataset for anomalies: ..."}
]
);
...
client = OpenAI()
# Simulated attacker's input attempting to inject a malicious system prompt
attacker_input = ...
completion = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": attacker_input},
{"role": "user", "content": "Compose a poem that explains the concept of recursion in programming."}
]
)
@GetMapping("/prompt_injection_persistent")
String generation(String userInput1, ...) {
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM users WHERE ...");
String userName = "";
if (rs != null) {
rs.next();
userName = rs.getString("userName");
}
return this.clientBuilder.build().prompt()
.system("Assist the user " + userName)
.user(userInput1)
.call()
.content();
}
client = new Anthropic();
# Simulated attacker's input attempting to inject a malicious system prompt
attacker_query = ...;
attacker_name = db.qyery('SELECT name FROM user_profiles WHERE ...');
response = client.messages.create(
model = "claude-3-5-sonnet-20240620",
max_tokens=2048,
system = "Provide assistance to the user " + attacker_name,
messages = [
{"role": "user", "content": attacker_query}
]
);
...
client = OpenAI()
# Simulated attacker's input attempting to inject a malicious system prompt
attacker_name = cursor.fetchone()['name']
attacker_query = ...
completion = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "Provide assistance to the user " + attacker_name},
{"role": "user", "content": attacker_query}
]
)
Object.prototype
을 가리키므로 개체 프로토타입을 덮어쓸 수 있는 공격자는 보통 Object.prototype
의 정의도 덮어쓸 수 있습니다. 그러면 응용 프로그램 내의 모든 개체가 영향을 받게 됩니다.undefined
로 설정할 수 있는 경우 프로토타입이 오염되면 응용 프로그램이 올바른 개체가 아닌 프로토타입에서 속성을 잘못 읽을 수도 있습니다.lodash
의 취약한 버전을 사용하여 개체의 프로토타입을 오염시킵니다.
import * as lodash from 'lodash'
...
let clonedObject = lodash.merge({}, JSON.parse(untrustedInput));
...
{"__proto__": { "isAdmin": true}}
라면 Object.prototype
에서 isAdmin = true
가 정의됩니다.
...
let config = {}
if (isAuthorizedAsAdmin()){
config.isAdmin = true;
}
...
if (config.isAdmin) {
// do something as the admin
}
...
isAdmin
은 isAuthorizedAdmin()
이 true를 반환하는 경우에만 true로 설정되어야 합니다. 그런데 응용 프로그램이 else 조건에서 config.isAdmin = false
를 설정하지 않으므로 config.isAdmin === undefined === false
가 사용됩니다.config
의 프로토타입은 이제 isAdmin === true
로 설정되었습니다. 따라서 관리자 인증을 우회할 수 있습니다.