CVE-2020-13432: Buffer Copy without Checking Size of Input ('Classic Buffer Overflow') (CWE-120)
value: rejetto HFS (aka HTTP File Server) v2.3m Build #300, when virtual files or folders are used, allows remote attackers to trigger an invalid-pointer write access violation via concurrent HTTP requests with a long URI or long HTTP headers.
CWE description: The product copies an input buffer to an output buffer without verifying that the size of the input buffer is less than the size of the output buffer, leading to a buffer overflow.
CVSS v3 base score: 7.5
Published: 2020-06-08T18:15Z
Repository: https://github.com/rejetto/hfs2
Language: Other
Files changed: main.dfm, main.pas, scriptLib.pas
Commit date: 2020-05-22 13:38:15 +0200
Commit message: limit URL parameters to 1000 characters

Diff: diff --git a/main.dfm b/main.dfm
index ca6f447..289e264 100644
--- a/main.dfm
+++ b/main.dfm
@@ -1,11 +1,11 @@
 object mainFrm: TmainFrm
   Left = 293
   Top = 219
   Caption = 'HFS ~ HTTP File Server'
-  ClientHeight = 391
-  ClientWidth = 913
+  ClientHeight = 483
+  ClientWidth = 879
   Color = clBtnFace
   Constraints.MinHeight = 260
   Constraints.MinWidth = 390
   Font.Charset = DEFAULT_CHARSET
   Font.Color = clWindowText
@@ -25,11 +25,11 @@ object mainFrm: TmainFrm
   PixelsPerInch = 96
   TextHeight = 14
   object graphSplitter: TSplitter
     Left = 0
     Top = 78
-    Width = 913
+    Width = 879
     Height = 5
     Cursor = crVSplit
     Align = alTop
     AutoSnap = False
     Beveled = True
@@ -40,11 +40,11 @@ object mainFrm: TmainFrm
     ExplicitWidth = 752
   end
   object graphBox: TPaintBox
     Left = 0
     Top = 48
-    Width = 913
+    Width = 879
     Height = 30
     Hint = 'Pink = Out'#13#10'Yellow = In'
     Align = alTop
     Font.Charset = DEFAULT_CHARSET
     Font.Color = clWindowText
@@ -60,11 +60,11 @@ object mainFrm: TmainFrm
     ExplicitWidth = 752
   end
   object topToolbar: TToolBar
     Left = 0
     Top = 0
-    Width = 913
+    Width = 879
     Height = 24
     AutoSize = True
     ButtonWidth = 150
     Caption = 'topToolbar'
     EdgeBorders = [ebBottom]
@@ -76,10 +76,11 @@ object mainFrm: TmainFrm
     Images = images
     List = True
     ParentFont = False
     ShowCaptions = True
     TabOrder = 1
+    ExplicitWidth = 976
     object menuBtn: TToolButton
       Left = 0
       Top = 0
       Hint = 'Hit ALT or F10 to pop it up'
       AutoSize = True
@@ -171,11 +172,11 @@ object mainFrm: TmainFrm
     end
   end
   object urlToolbar: TToolBar
     Left = 0
     Top = 24
-    Width = 913
+    Width = 879
     Height = 24
     AutoSize = True
     ButtonWidth = 122
     EdgeBorders = [ebBottom]
     Font.Charset = DEFAULT_CHARSET
@@ -187,10 +188,11 @@ object mainFrm: TmainFrm
     List = True
     ParentFont = False
     ShowCaptions = True
     TabOrder = 2
     Wrapable = False
+    ExplicitWidth = 976
     object browseBtn: TToolButton
       Left = 0
       Top = 0
       AutoSize = True
       Caption = 'Open in browser'
@@ -215,36 +217,37 @@ object mainFrm: TmainFrm
     end
   end
   object centralPnl: TPanel
     Left = 0
     Top = 83
-    Width = 913
-    Height = 308
+    Width = 879
+    Height = 400
     Align = alClient
     BevelOuter = bvNone
     Font.Charset = DEFAULT_CHARSET
     Font.Color = clWindowText
     Font.Height = -12
     Font.Name = 'Tahoma'
     Font.Style = []
     ParentFont = False
     TabOrder = 0
+    ExplicitWidth = 976
     object splitV: TSplitter
       Left = 313
       Top = 0
-      Height = 197
+      Height = 289
       Beveled = True
       Constraints.MaxWidth = 3
       Constraints.MinWidth = 3
       ResizeStyle = rsUpdate
       OnMoved = splitVMoved
       ExplicitHeight = 219
     end
     object splitH: TSplitter
       Left = 0
-      Top = 197
-      Width = 913
+      Top = 289
+      Width = 879
       Height = 5
       Cursor = crVSplit
       Align = alBottom
       Beveled = True
       MinSize = 1
@@ -254,20 +257,21 @@ object mainFrm: TmainFrm
       ExplicitWidth = 732
     end
     object logPnl: TPanel
       Left = 316
       Top = 0
-      Width = 597
-      Height = 197
+      Width = 563
+      Height = 289
       Align = alClient
       BevelOuter = bvNone
       TabOrder = 1
+      ExplicitWidth = 660
       object logBox: TRichEdit
         Left = 0
         Top = 23
-        Width = 597
-        Height = 174
+        Width = 563
+        Height = 266
         Align = alClient
         Font.Charset = ANSI_CHARSET
         Font.Color = clWindowText
         Font.Height = -12
         Font.Name = 'Tahoma'
@@ -280,38 +284,42 @@ object mainFrm: TmainFrm
         TabOrder = 0
         WordWrap = False
         Zoom = 100
         OnChange = logBoxChange
         OnMouseDown = logBoxMouseDown
+        ExplicitWidth = 660
       end
       object logTitle: TPanel
         Left = 0
         Top = 0
-        Width = 597
+        Width = 563
         Height = 23
         Align = alTop
         BevelOuter = bvNone
         TabOrder = 1
+        ExplicitWidth = 660
         object titlePnl: TPanel
           Left = 0
           Top = 0
-          Width = 337
+          Width = 303
           Height = 23
           Align = alClient
           BevelOuter = bvNone
           Caption = 'Log'
           TabOrder = 0
+          ExplicitWidth = 400
         end
         object logToolbar: TPanel
-          Left = 337
+          Left = 303
           Top = 0
           Width = 260
           Height = 23
           Align = alRight
           AutoSize = True
           BevelOuter = bvNone
           TabOrder = 1
+          ExplicitLeft = 400
           object collapsedPnl: TPanel
             Left = 0
             Top = 0
             Width = 21
             Height = 23
@@ -555,20 +563,20 @@ object mainFrm: TmainFrm
     end
     object filesPnl: TPanel
       Left = 0
       Top = 0
       Width = 313
-      Height = 197
+      Height = 289
       Align = alLeft
       BevelOuter = bvNone
       Caption = 'filesPnl'
       TabOrder = 0
       object filesBox: TTreeView
         Left = 0
         Top = 23
         Width = 313
-        Height = 174
+        Height = 266
         Align = alClient
         BevelInner = bvLowered
         BevelOuter = bvSpace
         Constraints.MinWidth = 50
         DragMode = dmAutomatic
@@ -614,32 +622,34 @@ object mainFrm: TmainFrm
         TabOrder = 1
       end
     end
     object connPnl: TPanel
       Left = 0
-      Top = 202
-      Width = 913
+      Top = 294
+      Width = 879
       Height = 106
       Align = alBottom
       BevelOuter = bvNone
       TabOrder = 2
+      ExplicitWidth = 976
       object sbar: TStatusBar
         Left = 0
         Top = 87
-        Width = 913
+        Width = 879
         Height = 19
         Panels = <
           item
             Width = 2000
           end>
         OnDblClick = sbarDblClick
         OnMouseDown = sbarMouseDown
+        ExplicitWidth = 976
       end
       object connBox: TListView
         Left = 0
         Top = 0
-        Width = 913
+        Width = 879
         Height = 87
         Align = alClient
         Columns = <
           item
             Caption = 'IP address'
@@ -658,10 +668,11 @@ object mainFrm: TmainFrm
             Width = 206
           end
           item
             Alignment = taCenter
             Caption = 'Speed'
+            Width = 100
           end
           item
             Alignment = taCenter
             Caption = 'Time left'
           end
@@ -682,10 +693,11 @@ object mainFrm: TmainFrm
         SmallImages = images
         TabOrder = 1
         ViewStyle = vsReport
         OnAdvancedCustomDrawSubItem = connBoxAdvancedCustomDrawSubItem
         OnData = connBoxData
+        ExplicitWidth = 976
       end
     end
   end
   object filemenu: TPopupMenu
     Images = images
@@ -3151,12 +3163,12 @@ object mainFrm: TmainFrm
     end
   end
   object connmenu: TPopupMenu
     Images = images
     OnPopup = connmenuPopup
-    Left = 248
-    Top = 320
+    Left = 264
+    Top = 408
     object Kickconnection1: TMenuItem
       Caption = 'Kick connection'
       OnClick = Kickconnection1Click
     end
     object KickIPaddress1: TMenuItem
@@ -3270,11 +3282,10 @@ object mainFrm: TmainFrm
         Caption = 'Disconnections'
       end
       object logRequestsChk: TMenuItem
         AutoCheck = True
         Caption = 'Requests'
-        Checked = True
       end
       object DumprequestsChk: TMenuItem
         AutoCheck = True
         Caption = 'Requests dump'
       end
diff --git a/main.pas b/main.pas
index 41619b1..37ae6b7 100644
--- a/main.pas
+++ b/main.pas
@@ -4779,20 +4779,27 @@ var
   data.countAsDownload:=FALSE;
   getPage(if_(was=data.disconnectReason, 'max contemp downloads', 'deny'), data);
   end; // limitsExceededOnDownload
 
   procedure extractParams();
+  const
+    MAX = 1000;
   var
     s: string;
     i: integer;
   begin
   s:=url;
   url:=chop('?',s);
   s:=replaceStr(s,'+',' ');
   data.urlvars.text:=s;
   for i:=0 to data.urlvars.count-1 do
-    data.urlvars[i]:=decodeURL(ansistring(data.urlvars[i]));
+    begin
+    s:=decodeURL(ansistring(data.urlvars[i]));
+    if length(s) > MAX then
+      setLength(s, MAX);
+    data.urlvars[i]:=s;
+    end;
   end; // extractParams
 
   procedure closeUploadingFile();
   begin
   if data.f = NIL then exit;
diff --git a/scriptLib.pas b/scriptLib.pas
index 238dc5e..09efc16 100644
--- a/scriptLib.pas
+++ b/scriptLib.pas
@@ -1781,14 +1781,11 @@ try
       handleSymbol();
       exit;
       end;
 
     if not mainfrm.enableMacrosChk.checked then
-      begin
-      result:=fullMacro;
-      exit;
-      end;
+      exit(fullMacro);
 
     if pars.count = 0 then exit;
     // extract first parameter as 'name'
     name:=trim(pars[0]);
     pars.delete(0);    // this operation is done with a memory move over pointers. Having few parameters normally, it's fast. We may eventually avoid this deletion and consider parameters starting from 1.

Vulnerable code:   ClientHeight = 391
  ClientWidth = 913
    Width = 913
    Width = 913
    Width = 913
    Width = 913
    Width = 913
    Height = 308
      Height = 197
      Top = 197
      Width = 913
      Width = 597
      Height = 197
        Width = 597
        Height = 174
        Width = 597
          Width = 337
          Left = 337
      Height = 197
        Height = 174
      Top = 202
      Width = 913
        Width = 913
        Width = 913
    Left = 248
    Top = 320
        Checked = True
    data.urlvars[i]:=decodeURL(ansistring(data.urlvars[i]));
      begin
      result:=fullMacro;
      exit;
      end;
Fixed code:   ClientHeight = 483
  ClientWidth = 879
    Width = 879
    Width = 879
    Width = 879
    ExplicitWidth = 976
    Width = 879
    ExplicitWidth = 976
    Width = 879
    Height = 400
    ExplicitWidth = 976
      Height = 289
      Top = 289
      Width = 879
      Width = 563
      Height = 289
      ExplicitWidth = 660
        Width = 563
        Height = 266
        ExplicitWidth = 660
        Width = 563
        ExplicitWidth = 660
          Width = 303
          ExplicitWidth = 400
          Left = 303
          ExplicitLeft = 400
      Height = 289
        Height = 266
      Top = 294
      Width = 879
      ExplicitWidth = 976
        Width = 879
        ExplicitWidth = 976
        Width = 879
            Width = 100
        ExplicitWidth = 976
    Left = 264
    Top = 408
  const
    MAX = 1000;
    begin
    s:=decodeURL(ansistring(data.urlvars[i]));
    if length(s) > MAX then
      setLength(s, MAX);
    data.urlvars[i]:=s;
    end;
      exit(fullMacro);