[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f0igVPdhqlFzG-by2yygkHN2IPoP2s_0U2XkWlSkg8QU":3},{"id":4,"question":5,"answer":6,"answerHtml":7,"slug":8,"keywords":9,"article":10,"status":34,"aiModel":39,"aiConfidence":39,"updatedAt":51,"createdAt":51,"_status":50},451,"Where are the Last WebAdmin Sessions records actually stored, and how can they be cleared?","The records are stored in two locations: the reporting database (table confd_sessions) and the log file \u002Fvar\u002Flog\u002Fconfd.log. To clear them, you can delete entries from confd_sessions using SQL commands via psql (e.g., `DELETE FROM confd_sessions WHERE facility IN ('webadmin','acc-agent','acc_sso')`) and remove corresponding lines from the log file. This forensic cleaning process is detailed in the [Sophos UTM Analysis - Clearing Last WebAdmin Sessions Records](\u002Fnews\u002Fsophos-utm-analysis-clearing-last-webadmin-sessions-records) article.","\u003Cp>The records are stored in two locations: the reporting database (table confd_sessions) and the log file \u002Fvar\u002Flog\u002Fconfd.log. To clear them, you can delete entries from confd_sessions using SQL commands via psql (e.g., `DELETE FROM confd_sessions WHERE facility IN (&#39;webadmin&#39;,&#39;acc-agent&#39;,&#39;acc_sso&#39;)`) and remove corresponding lines from the log file. This forensic cleaning process is detailed in the [Sophos UTM Analysis - Clearing Last WebAdmin Sessions Records](\u002Fnews\u002Fsophos-utm-analysis-clearing-last-webadmin-sessions-records) article.\u003C\u002Fp>\u003Cp>\u003Ca href=\"\u002Fnews\u002Fsophos-utm-analysis-clearing-last-webadmin-sessions-records\">Read the related One Day Sec article\u003C\u002Fa>\u003C\u002Fp>","where-are-the-last-webadmin-sessions-records-actually-stored-and-how-can-they-be-1777483657807","database, confd_sessions, log file, psql, DELETE",{"id":11,"title":12,"slug":13,"description":14,"content":15,"contentHtml":30,"cover":31,"author":32,"views":19,"readingTime":33,"status":34,"publishedAt":35,"seo":36,"tags":41,"qaPairs":42,"meta":47,"updatedAt":48,"createdAt":49,"_status":50},113,"Sophos UTM Analysis - Clearing Last WebAdmin Sessions Records","sophos-utm-analysis-clearing-last-webadmin-sessions-records","Learn how to clear Last WebAdmin Sessions records on Sophos UTM devices through technical analysis, including research steps and implementation methods.",{"root":16},{"type":17,"format":18,"indent":19,"version":20,"children":21,"direction":29},"root","",0,1,[22],{"type":23,"format":18,"indent":19,"version":20,"children":24,"direction":29},"paragraph",[25],{"mode":26,"text":27,"type":28,"style":18,"detail":19,"format":19,"version":20},"normal","\u003Chtml>\u003Chead>\u003C\u002Fhead>\u003Cbody>\u003Ch2>0x00 Preface\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>For Sophos UTM devices, the Last WebAdmin Sessions in the web management page records each user login. This article introduces methods to clear specific Last WebAdmin Sessions records solely from a technical research perspective, documenting research details.\u003C\u002Fp>\u003Ch2>0x01 Introduction\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>This article will cover the following:\u003C\u002Fp>\u003Cul>\u003Cli>Research Process\u003C\u002Fli>\u003Cli>Implementation Methods\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>0x02 Introduction to Last WebAdmin Sessions\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>In the web management page, selecting Management displays the Last WebAdmin Sessions records, as shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770017314627_0_ddeb6f22b5.png\">\u003C\u002Fp>\u003Cp>The records include the following:\u003C\u002Fp>\u003Cul>\u003Cli>User: Login username\u003C\u002Fli>\u003Cli>Start: Login Time\u003C\u002Fli>\u003Cli>State: Logout Time\u003C\u002Fli>\u003Cli>IP address: Login IP\u003C\u002Fli>\u003Cli>Changelog: Modified Configuration\u003C\u002Fli>\u003C\u002Ful>\u003Cp>For Changelog, clicking Show will display the modified configuration, as shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770017362060_1_035a37bb6b.png\">\u003C\u002Fp>\u003Cp>Under default settings, Last WebAdmin Sessions will display the most recent 20 records\u003C\u002Fp>\u003Ch2>0x03 Research Process\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Ch3>1. Attempt to modify \u002Fvar\u002Fconfd\u002Fvar\u002Fstorage\u002Fcfg\u003C\u002Fh3>\u003Cp>As mentioned in the previous article 'Sophos UTM Exploitation Analysis—Exporting Configuration Files', \u002Fvar\u002Fconfd\u002Fvar\u002Fstorage\u002Fcfg stores the configuration information of Sophos UTM, so it is speculated that clearing Last WebAdmin Sessions records can be achieved by modifying the \u002Fvar\u002Fconfd\u002Fvar\u002Fstorage\u002Fcfg file\u003C\u002Fp>\u003Cp>The file format of \u002Fvar\u002Fconfd\u002Fvar\u002Fstorage\u002Fcfg is Perl Storable files, and StorableEdit is used here to edit the file\u003C\u002Fp>\u003Cp>Upload the file storableedit-1.5.pl to Sophos UTM and execute the command:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>.\u002Fstorableedit-1.5.pl cfg\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>The result is as shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770017390368_2_7500e2adf9.png\">\u003C\u002Fp>\u003Cp>The parsed file structure is consistent with the results exported using SophosUTM_ConfigParser.py\u003C\u002Fp>\u003Cp>To view configuration information, use the following commands:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>cd lastchange\u003Cbr>cd REF_AaaGroGroup1\u003Cbr>ls\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>To clear all attributes, use the following commands:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>$cur-&gt;{'user'} = '',$cur-&gt;{'time'} = '',$cur-&gt;{'sid'} = '',$cur-&gt;{'srcip'} = ''\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>To save the file, use the following command:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>x\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>However, modifying the cfg file will not affect the Last WebAdmin Sessions records\u003C\u002Fp>\u003Ch3>2. Decompile the source code of the web management page\u003C\u002Fh3>\u003Cp>Path to the web management page program file: \u002Fvar\u002Fsec\u002Fchroot-httpd\u002Fvar\u002Fwebadmin\u002Fwebadmin.plx\u003C\u002Fp>\u003Cp>Use SophosUTM_plxDecrypter.py to decompile \u002Fvar\u002Fsec\u002Fchroot-httpd\u002Fvar\u002Fwebadmin\u002Fwebadmin.plx\u003C\u002Fp>\u003Cp>Locate the key file: export-webadmin.plx\\wfe\\asg\\modules\\asg_dashboard.pm\u003C\u002Fp>\u003Cp>Locate key content: my $userlog = $sys-&gt;userlog_read(max =&gt; 20, facility =&gt; 'webadmin,acc-agent,acc_sso') || [];\u003C\u002Fp>\u003Cp>As shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770017416530_3_4f0bfb6cd8.png\">\u003C\u002Fp>\u003Cp>Locate the key function from the output: userlog_read\u003C\u002Fp>\u003Ch3>3. Locate the key function userlog_read\u003C\u002Fh3>\u003Cp>Google search $sys-&gt;userlog_read, find a reference document: https:\u002F\u002Fcommunity.sophos.com\u002Futm-firewall\u002Fastaroorg\u002Ff\u002Fasg-v8-000-beta-closed\u002F69661\u002F7-920-bug-open-failed-smtp-relay-login-is-showing-up-on-last-webadmin-logins\u003C\u002Fp>\u003Cp>The document contains some descriptions about userlog_read, as shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770017463049_4_ba2d3f0865.png\">\u003C\u002Fp>\u003Cp>From the description, it is concluded that userlog_read is related to the cc command\u003C\u002Fp>\u003Ch3>4. Decompile the process corresponding to the cc command\u003C\u002Fh3>\u003Cp>The file corresponding to the cc command is \u002Fvar\u002Fconfd\u002Fconfd.plx, use SophosUTM_plxDecrypter.py to decompile \u002Fvar\u002Fconfd\u002Fconfd.plx\u003C\u002Fp>\u003Ch3>5. Obtain details of the function userlog_read\u003C\u002Fh3>\u003Cp>Search for content related to userlog_read, command as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>grep -iR \"userlog_read\" \u002Fhome\u002Fkali\u002F1\u002Fdecrypt\u002FExport-confd.plx\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>The output result is as shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fuploads\u002Fdocx_image_1770017478649_5_687bff0ad3.png\">\u003C\u002Fp>\u003Cp>Locate key files from output results: Export-confd.plx\u002FInfo\u002Fwebadmin\u002Flog.pm\u003C\u002Fp>\u003Cp>Locate function definition:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>sub userlog_read {\u003Cbr>  my ($self, %args) = @_;\u003Cbr>  $args{max} = $args{sid} ? 1 : $args{max} || 20;\u003Cbr>  $args{facility} = { map {($_ =&gt; 1)} split \u002F,\u002F, $args{facility} }\u003Cbr>    if $args{facility};\u003Cbr>\u003Cbr>  my $sessions;\u003Cbr>  $sessions = _consult_db($self, \\%args)\u003Cbr>    unless $self-&gt;get(qw(reporting userlog_from_logs));\u003Cbr>  $sessions = _iterate_files($self, \\%args)\u003Cbr>    unless ref $sessions eq 'ARRAY';\u003Cbr>\u003Cbr>  foreach my $sd (@$sessions) {\u003Cbr>    $sd-&gt;{state} = (-e \"$config::session_dir\u002F$sd-&gt;{sid}\" ? 'active' : 'ended')\u003Cbr>      if ! $sd-&gt;{state} || $sd-&gt;{state} eq 'active';\u003Cbr>  }\u003Cbr>\u003Cbr>  return $sessions;\u003Cbr>}\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch3>6. Analysis of userlog_read function code\u003C\u002Fh3>\u003Cp>The code involves two operations: reading from the database and reading from a file, details as follows:\u003C\u002Fp>\u003Ch4>(1) Database operation\u003C\u002Fh4>\u003Cp>Key code:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>sub _consult_db {\u003Cbr>  my ($self, $args) = @_;\u003Cbr>\u003Cbr>  my $facility_selection = '';\u003Cbr>  $facility_selection = 'WHERE facility in ('.\u003Cbr>    join( ',', map { '?' } keys %{$args-&gt;{facility}} ).') '\u003Cbr>    if $args-&gt;{facility};\u003Cbr>  my %sql = (\u003Cbr>    sessions =&gt; 'SELECT sid, facility, srcip, username, time, endtime, state '\u003Cbr>                .'FROM confd_sessions '.$facility_selection\u003Cbr>                .'ORDER BY time DESC LIMIT ?',\u003Cbr>    session  =&gt; 'SELECT sid, facility, srcip, username, time, endtime, state '\u003Cbr>                .'FROM confd_sessions WHERE sid = ?',\u003Cbr>    nodes    =&gt; 'SELECT * FROM confd_nodes WHERE sid = $1 ORDER BY time DESC',\u003Cbr>    objects  =&gt; 'SELECT * FROM confd_objects WHERE sid = $1 ORDER BY time DESC',\u003Cbr>  );\u003Cbr>\u003Cbr>  # Prepare database access.\u003Cbr>  my $db = Astaro::ADBS-&gt;new(dbName =&gt; 'reporting') or return;\u003Cbr>  while (my ($key, $query) = each %sql) {\u003Cbr>    $db-&gt;registerSQL($key, $query) or return;\u003Cbr>  }\u003Cbr>\u003Cbr>  # List Confd sessions.\u003Cbr>  my $sessh;\u003Cbr>  if ($args-&gt;{sid}) {\u003Cbr>    $sessh = $db-&gt;getHandle('session') or return;\u003Cbr>    $sessh-&gt;execute($args-&gt;{sid}) or return;\u003Cbr>  } elsif( $args-&gt;{facility} ) {\u003Cbr>    $sessh = $db-&gt;getHandle('sessions') or return;\u003Cbr>    $sessh-&gt;execute(keys %{$args-&gt;{facility}}, $args-&gt;{max}) or return;\u003Cbr>  } else {\u003Cbr>    $sessh = $db-&gt;getHandle('sessions') or return;\u003Cbr>    $sessh-&gt;execute($args-&gt;{max}) or return;\u003Cbr>  }\u003Cbr>  my $sessions = $sessh-&gt;fetchall_arrayref({});\u003Cbr>  my $nodeh = $db-&gt;getHandle('nodes') or return;\u003Cbr>  my $objh = $db-&gt;getHandle('objects') or return;\u003Cbr>  foreach my $sd (@$sessions) {\u003Cbr>\u003Cbr>    # Tweak session data.\u003Cbr>    $sd-&gt;{time} =~ tr\u002F- \u002F:-\u002F;\u003Cbr>    $sd-&gt;{endtime} =~ tr\u002F- \u002F:-\u002F if defined $sd-&gt;{endtime};\u003Cbr>    $sd-&gt;{user} = delete $sd-&gt;{username};  # user is a reserved word in SQL\u003Cbr>    $sd-&gt;{user} .= ' (SUM)' if $sd-&gt;{facility} eq 'acc_sso';\u003Cbr>    $sd-&gt;{user} = utils::Sanitize::sanitize($sd-&gt;{user}) if $sd-&gt;{user};\u003Cbr>\u003Cbr>    # Fetch node changes.\u003Cbr>    $nodeh-&gt;execute($sd-&gt;{sid}) or return;\u003Cbr>    foreach my $node (@{ $nodeh-&gt;fetchall_arrayref({}) }) {\u003Cbr>      $node-&gt;{time} =~ tr\u002F- \u002F:-\u002F;\u003Cbr>      $node-&gt;{node_descr} = Message::get_phrase(\u003Cbr>        'N', $node, { Nattrs =&gt; ['node'] });\u003Cbr>      $sd-&gt;{main}{$node-&gt;{node}} ||= [];\u003Cbr>      push @{$sd-&gt;{main}{$node-&gt;{node}}}, $node;\u003Cbr>    }\u003Cbr>    \u003Cbr>    # Fetch object changes.\u003Cbr>    $objh-&gt;execute($sd-&gt;{sid}) or return;\u003Cbr>    foreach my $object (@{ $objh-&gt;fetchall_arrayref({}) }) {\u003Cbr>      my $attrs = $object-&gt;{attrs} || [];\u003Cbr>      $object-&gt;{attributes} = [];\u003Cbr>      while (@$attrs) {\u003Cbr>        my $name = shift @$attrs;\u003Cbr>        $object-&gt;{\"attr_$name\"} = shift @$attrs;\u003Cbr>        $object-&gt;{\"oldattr_$name\"} = shift @$attrs;\u003Cbr>        $object-&gt;{\"descr_$name\"} = Message::get_phrase(\u003Cbr>          'A', $object, { attr =&gt; $name });\u003Cbr>        push @{$object-&gt;{attributes}}, $name;\u003Cbr>      }\u003Cbr>      delete $object-&gt;{attrs};\u003Cbr>      if (@{$object-&gt;{attributes}}) {\u003Cbr>        $object-&gt;{attributes} = [ sort @{$object-&gt;{attributes}} ];\u003Cbr>      } else {\u003Cbr>        delete $object-&gt;{attributes};\u003Cbr>      }\u003Cbr>      $object-&gt;{time} =~ tr\u002F- \u002F:-\u002F;\u003Cbr>      $object-&gt;{obj_descr} = Message::get_phrase('O', $object, {});\u003Cbr>      $sd-&gt;{objects}{$object-&gt;{ref}} ||= [];\u003Cbr>      push @{$sd-&gt;{objects}{$object-&gt;{ref}}}, $object;\u003Cbr>    }\u003Cbr>  }\u003Cbr>  $db-&gt;disconnect;\u003Cbr>\u003Cbr>  return $sessions;\u003Cbr>}\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Code Analysis:\u003C\u002Fp>\u003Cp>The following operations are executed from the reporting database to achieve data reading:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>sessions:   SELECT sid,facility,srcip,username,time,endtime,state FROM confd_sessions;\u003Cbr>nodes:      SELECT * FROM confd_nodes;\u003Cbr>objects:    SELECT * FROM confd_objects;\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Through testing and analysis, confd_sessions stores Session information\u003C\u002Fp>\u003Cp>CMD command to read Session information:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>psql reporting -U postgres -c 'SELECT sid,facility,srcip,username,time,endtime,state FROM confd_sessions;'\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch4>(2) File Operations\u003C\u002Fh4>\u003Cp>Key code:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>sub _iterate_files {\u003Cbr>  my ($self, $args) = @_;\u003Cbr>\u003Cbr>  # choose the first file to process\u003Cbr>  my $filename = '\u002Fvar\u002Flog\u002Fconfd.log';\u003Cbr>  if (defined $args-&gt;{time}) {\u003Cbr>    my @then;\u003Cbr>    if ($args-&gt;{time} =~ \u002F^(\\d{4}):(\\d\\d):(\\d\\d)\u002F) {\u003Cbr>      @then = (0, 0, 12, $3, $2-1, $1-1900);\u003Cbr>    } else {\u003Cbr>      @then  = localtime($args-&gt;{time});\u003Cbr>    }\u003Cbr>    my $then  = POSIX::strftime('%F', @then);\u003Cbr>    my $now   = POSIX::strftime('%F', localtime);\u003Cbr>    $filename = POSIX::strftime(\u003Cbr>      '\u002Fvar\u002Flog\u002Fconfd\u002F%Y\u002F%m\u002Fconfd-%Y-%m-%d.log.gz',\u003Cbr>      @then,\u003Cbr>    ) if $then ne $now;\u003Cbr>  }\u003Cbr>\u003Cbr>  # process the first file\u003Cbr>  my $sessions = [];\u003Cbr>  my $sdata = {};\u003Cbr>  _parse_file($self, $filename, $sessions, $sdata, $args);\u003Cbr>\u003Cbr>  # if needed, process archived log files\u003Cbr>  if (@$sessions &lt; $args-&gt;{max} &amp;&amp; not $args-&gt;{time}) {\u003Cbr>    my $iter = File::Next::files({\u003Cbr>      file_filter =&gt; sub { \u002F\\.log\\.gz$\u002F },\u003Cbr>      sort_files =&gt; \\&amp;File::Next::sort_reverse,\u003Cbr>    }, '\u002Fvar\u002Flog\u002Fconfd');\u003Cbr>    while (@$sessions &lt; $args-&gt;{max}) {\u003Cbr>      $filename = $iter-&gt;();\u003Cbr>      last unless defined $filename;\u003Cbr>      my @new_sessions;\u003Cbr>      _parse_file($self, $filename, \\@new_sessions, $sdata, $args);\u003Cbr>      push @$sessions, @new_sessions;\u003Cbr>    }\u003Cbr>  }\u003Cbr>\u003Cbr>  # limit the number of sessions to report on\u003Cbr>  splice @$sessions, $args-&gt;{max} if @$sessions &gt;= $args-&gt;{max};\u003Cbr>  return [ @{$sdata}{@$sessions} ];\u003Cbr>}\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Code Analysis:\u003C\u002Fp>\u003Cp>Read the file \u002Fvar\u002Flog\u002Fconfd.log. \u002Fvar\u002Flog\u002Fconfd.log only stores logs from the current time back to a certain period. Logs from earlier times are saved in \u002Fvar\u002Flog\u002Fconfd\u002F%Y\u002F%m\u002Fconfd-%Y-%m-%d.log.gz. For example, logs from May 16, 2022, are located at \u002Fvar\u002Flog\u002Fconfd\u002F2022\u002F05\u002Fconfd-2022-05-16.log.gz.\u003C\u002Fp>\u003Cp>Through testing and analysis, \u002Fvar\u002Flog\u002Fconfd.log stores Session information.\u003C\u002Fp>\u003Ch3>7. Edit the Session information stored in the file.\u003C\u002Fh3>\u003Cp>View successful login information:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>cat \u002Fvar\u002Flog\u002Fconfd.log | grep success\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Example of returned result:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>2022:05:23-00:19:33 test confd[41177]: I Role::authenticate:185() =&gt; id=\"3106\" severity=\"info\" sys=\"System\" sub=\"confd\" name=\"authentication successful\" user=\"admin\" srcip=\"192.168.1.2\" sid=\"8ad7bbf2781b006d99176eea9050694811e745e04acfab3dd0179620109a41ab\" facility=\"webadmin\" client=\"webadmin.plx\" call=\"new\"&lt;31&gt;May 23 00:19:33 confd[41177]: D sys::AUTOLOAD:307() =&gt; id=\"3100\" severity=\"debug\" sys=\"System\" sub=\"confd\" name=\"external call\" user=\"admin\" srcip=\"192.168.1.2\" facility=\"webadmin\" client=\"webadmin.plx\" lock=\"none\" method=\"get_SID\"\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>From the result, obtain the sid as 8ad7bbf2781b006d99176eea9050694811e745e04acfab3dd0179620109a41ab.\u003C\u002Fp>\u003Cp>Filter information for the specified sid:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>cat \u002Fvar\u002Flog\u002Fconfd.log | grep 8ad7bbf2781b006d99176eea9050694811e745e04acfab3dd0179620109a41ab\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Example of returned result:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>2022:05:23-00:19:33 test confd[41177]: I Role::authenticate:185() =&gt; id=\"3106\" severity=\"info\" sys=\"System\" sub=\"confd\" name=\"authentication successful\" user=\"admin\" srcip=\"192.168.1.2\" sid=\"8ad7bbf2781b006d99176eea9050694811e745e04acfab3dd0179620109a41ab\" facility=\"webadmin\" client=\"webadmin.plx\" call=\"new\"&lt;31&gt;May 23 00:19:33 confd[41177]: D sys::AUTOLOAD:307() =&gt; id=\"3100\" severity=\"debug\" sys=\"System\" sub=\"confd\" name=\"external call\" user=\"admin\" srcip=\"192.168.1.2\" facility=\"webadmin\" client=\"webadmin.plx\" lock=\"none\" method=\"get_SID\"\u003Cbr>2022:05:23-00:50:24 test confd[5198]: I Session::terminate:292() =&gt; id=\"3100\" severity=\"info\" sys=\"System\" sub=\"confd\" name=\"closing session\" user=\"admin\" srcip=\"192.168.1.2\" sid=\"8ad7bbf2781b006d99176eea9050694811e745e04acfab3dd0179620109a41ab\" facility=\"webadmin\" client=\"webadmin.plx\" call=\"logout\" function=\"logout\"\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Extract from it:\u003C\u002Fp>\u003Cul>\u003Cli>authentication successful: 2022:05:23-00:19:33\u003C\u002Fli>\u003Cli>User: admin\u003C\u002Fli>\u003Cli>srcip: 192.168.1.2\u003C\u002Fli>\u003Cli>closing session: 2022:05:23-00:50:24\u003C\u002Fli>\u003C\u002Ful>\u003Cp>Comparing the above information with the Last WebAdmin Sessions in the Web management page Management, it is found that the data is consistent\u003C\u002Fp>\u003Cp>Delete the above information:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>sed -i \"\u002F8ad7bbf2781b006d99176eea9050694811e745e04acfab3dd0179620109a41ab\u002Fd\" \u002Fvar\u002Flog\u002Fconfd.log\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Refreshing the Web management page Management, it is found that this method cannot clear the Last WebAdmin Sessions records\u003C\u002Fp>\u003Ch3>8. Edit the Session information stored in the database\u003C\u002Fh3>\u003Cp>Query information for the specified sid:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>psql reporting -U postgres -c \"SELECT sid,facility,srcip,username,time,endtime,state FROM confd_sessions WHERE sid ='8ad7bbf2781b006d99176eea9050694811e745e04acfab3dd0179620109a41ab';\"\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Delete information for the specified sid:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>psql reporting -U postgres -c \"DELETE FROM confd_sessions WHERE sid ='f7cce7739e98229816be6b186ada2e2942064cbf0093e329e98939fe65d8d3e3';\"\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Refreshing the Web management page Management reveals that this method can clear the Last WebAdmin Sessions records (including Changelog)\u003C\u002Fp>\u003Ch2>0x04 Implementation Method\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>Based on the above content, the method to clear Last WebAdmin Sessions records is derived: delete the corresponding records in the reporting database\u003C\u002Fp>\u003Cp>Specific steps are as follows:\u003C\u002Fp>\u003Ch3>1. Confirm the sid corresponding to the Last WebAdmin Sessions records\u003C\u002Fh3>\u003Cp>Read the file \u002Fvar\u002Flog\u002Fconfd.log, query command:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>cat \u002Fvar\u002Flog\u002Fconfd.log| grep success\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>From the returned results, confirm the sid of the Session records\u003C\u002Fp>\u003Ch3>2. Delete the Session records corresponding to the sid\u003C\u002Fh3>\u003Cp>Command example:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>psql reporting -U postgres -c \"DELETE FROM confd_sessions WHERE sid ='f7cce7739e98229816be6b186ada2e2942064cbf0093e329e98939fe65d8d3e3';\"\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch2>0x05 Summary\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>This article details the method for clearing Last WebAdmin Sessions records.\u003C\u002Fp>\u003C\u002Fbody>\u003C\u002Fhtml>","text","ltr","\u003Chtml>\u003Chead>\u003C\u002Fhead>\u003Cbody>\u003Ch2>0x00 Preface\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>For Sophos UTM devices, the Last WebAdmin Sessions in the web management page records each user login. This article introduces methods to clear specific Last WebAdmin Sessions records solely from a technical research perspective, documenting research details.\u003C\u002Fp>\u003Ch2>0x01 Introduction\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>This article will cover the following:\u003C\u002Fp>\u003Cul>\u003Cli>Research Process\u003C\u002Fli>\u003Cli>Implementation Methods\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>0x02 Introduction to Last WebAdmin Sessions\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>In the web management page, selecting Management displays the Last WebAdmin Sessions records, as shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770017314627_0_ddeb6f22b5-1.png\">\u003C\u002Fp>\u003Cp>The records include the following:\u003C\u002Fp>\u003Cul>\u003Cli>User: Login username\u003C\u002Fli>\u003Cli>Start: Login Time\u003C\u002Fli>\u003Cli>State: Logout Time\u003C\u002Fli>\u003Cli>IP address: Login IP\u003C\u002Fli>\u003Cli>Changelog: Modified Configuration\u003C\u002Fli>\u003C\u002Ful>\u003Cp>For Changelog, clicking Show will display the modified configuration, as shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770017362060_1_035a37bb6b-1.png\">\u003C\u002Fp>\u003Cp>Under default settings, Last WebAdmin Sessions will display the most recent 20 records\u003C\u002Fp>\u003Ch2>0x03 Research Process\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Ch3>1. Attempt to modify \u002Fvar\u002Fconfd\u002Fvar\u002Fstorage\u002Fcfg\u003C\u002Fh3>\u003Cp>As mentioned in the previous article 'Sophos UTM Exploitation Analysis—Exporting Configuration Files', \u002Fvar\u002Fconfd\u002Fvar\u002Fstorage\u002Fcfg stores the configuration information of Sophos UTM, so it is speculated that clearing Last WebAdmin Sessions records can be achieved by modifying the \u002Fvar\u002Fconfd\u002Fvar\u002Fstorage\u002Fcfg file\u003C\u002Fp>\u003Cp>The file format of \u002Fvar\u002Fconfd\u002Fvar\u002Fstorage\u002Fcfg is Perl Storable files, and StorableEdit is used here to edit the file\u003C\u002Fp>\u003Cp>Upload the file storableedit-1.5.pl to Sophos UTM and execute the command:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>.\u002Fstorableedit-1.5.pl cfg\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>The result is as shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770017390368_2_7500e2adf9-1.png\">\u003C\u002Fp>\u003Cp>The parsed file structure is consistent with the results exported using SophosUTM_ConfigParser.py\u003C\u002Fp>\u003Cp>To view configuration information, use the following commands:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>cd lastchange\u003Cbr>cd REF_AaaGroGroup1\u003Cbr>ls\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>To clear all attributes, use the following commands:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>$cur-&gt;{'user'} = '',$cur-&gt;{'time'} = '',$cur-&gt;{'sid'} = '',$cur-&gt;{'srcip'} = ''\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>To save the file, use the following command:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>x\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>However, modifying the cfg file will not affect the Last WebAdmin Sessions records\u003C\u002Fp>\u003Ch3>2. Decompile the source code of the web management page\u003C\u002Fh3>\u003Cp>Path to the web management page program file: \u002Fvar\u002Fsec\u002Fchroot-httpd\u002Fvar\u002Fwebadmin\u002Fwebadmin.plx\u003C\u002Fp>\u003Cp>Use SophosUTM_plxDecrypter.py to decompile \u002Fvar\u002Fsec\u002Fchroot-httpd\u002Fvar\u002Fwebadmin\u002Fwebadmin.plx\u003C\u002Fp>\u003Cp>Locate the key file: export-webadmin.plx\\wfe\\asg\\modules\\asg_dashboard.pm\u003C\u002Fp>\u003Cp>Locate key content: my $userlog = $sys-&gt;userlog_read(max =&gt; 20, facility =&gt; 'webadmin,acc-agent,acc_sso') || [];\u003C\u002Fp>\u003Cp>As shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770017416530_3_4f0bfb6cd8-1.png\">\u003C\u002Fp>\u003Cp>Locate the key function from the output: userlog_read\u003C\u002Fp>\u003Ch3>3. Locate the key function userlog_read\u003C\u002Fh3>\u003Cp>Google search $sys-&gt;userlog_read, find a reference document: https:\u002F\u002Fcommunity.sophos.com\u002Futm-firewall\u002Fastaroorg\u002Ff\u002Fasg-v8-000-beta-closed\u002F69661\u002F7-920-bug-open-failed-smtp-relay-login-is-showing-up-on-last-webadmin-logins\u003C\u002Fp>\u003Cp>The document contains some descriptions about userlog_read, as shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770017463049_4_ba2d3f0865-1.png\">\u003C\u002Fp>\u003Cp>From the description, it is concluded that userlog_read is related to the cc command\u003C\u002Fp>\u003Ch3>4. Decompile the process corresponding to the cc command\u003C\u002Fh3>\u003Cp>The file corresponding to the cc command is \u002Fvar\u002Fconfd\u002Fconfd.plx, use SophosUTM_plxDecrypter.py to decompile \u002Fvar\u002Fconfd\u002Fconfd.plx\u003C\u002Fp>\u003Ch3>5. Obtain details of the function userlog_read\u003C\u002Fh3>\u003Cp>Search for content related to userlog_read, command as follows:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>grep -iR \"userlog_read\" \u002Fhome\u002Fkali\u002F1\u002Fdecrypt\u002FExport-confd.plx\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>The output result is as shown in the figure below\u003C\u002Fp>\u003Cp>\u003Cimg alt=\"Alt text\" src=\"\u002Fapi\u002Fmedia\u002Ffile\u002Fdocx_image_1770017478649_5_687bff0ad3-1.png\">\u003C\u002Fp>\u003Cp>Locate key files from output results: Export-confd.plx\u002FInfo\u002Fwebadmin\u002Flog.pm\u003C\u002Fp>\u003Cp>Locate function definition:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>sub userlog_read {\u003Cbr>  my ($self, %args) = @_;\u003Cbr>  $args{max} = $args{sid} ? 1 : $args{max} || 20;\u003Cbr>  $args{facility} = { map {($_ =&gt; 1)} split \u002F,\u002F, $args{facility} }\u003Cbr>    if $args{facility};\u003Cbr>\u003Cbr>  my $sessions;\u003Cbr>  $sessions = _consult_db($self, \\%args)\u003Cbr>    unless $self-&gt;get(qw(reporting userlog_from_logs));\u003Cbr>  $sessions = _iterate_files($self, \\%args)\u003Cbr>    unless ref $sessions eq 'ARRAY';\u003Cbr>\u003Cbr>  foreach my $sd (@$sessions) {\u003Cbr>    $sd-&gt;{state} = (-e \"$config::session_dir\u002F$sd-&gt;{sid}\" ? 'active' : 'ended')\u003Cbr>      if ! $sd-&gt;{state} || $sd-&gt;{state} eq 'active';\u003Cbr>  }\u003Cbr>\u003Cbr>  return $sessions;\u003Cbr>}\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch3>6. Analysis of userlog_read function code\u003C\u002Fh3>\u003Cp>The code involves two operations: reading from the database and reading from a file, details as follows:\u003C\u002Fp>\u003Ch4>(1) Database operation\u003C\u002Fh4>\u003Cp>Key code:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>sub _consult_db {\u003Cbr>  my ($self, $args) = @_;\u003Cbr>\u003Cbr>  my $facility_selection = '';\u003Cbr>  $facility_selection = 'WHERE facility in ('.\u003Cbr>    join( ',', map { '?' } keys %{$args-&gt;{facility}} ).') '\u003Cbr>    if $args-&gt;{facility};\u003Cbr>  my %sql = (\u003Cbr>    sessions =&gt; 'SELECT sid, facility, srcip, username, time, endtime, state '\u003Cbr>                .'FROM confd_sessions '.$facility_selection\u003Cbr>                .'ORDER BY time DESC LIMIT ?',\u003Cbr>    session  =&gt; 'SELECT sid, facility, srcip, username, time, endtime, state '\u003Cbr>                .'FROM confd_sessions WHERE sid = ?',\u003Cbr>    nodes    =&gt; 'SELECT * FROM confd_nodes WHERE sid = $1 ORDER BY time DESC',\u003Cbr>    objects  =&gt; 'SELECT * FROM confd_objects WHERE sid = $1 ORDER BY time DESC',\u003Cbr>  );\u003Cbr>\u003Cbr>  # Prepare database access.\u003Cbr>  my $db = Astaro::ADBS-&gt;new(dbName =&gt; 'reporting') or return;\u003Cbr>  while (my ($key, $query) = each %sql) {\u003Cbr>    $db-&gt;registerSQL($key, $query) or return;\u003Cbr>  }\u003Cbr>\u003Cbr>  # List Confd sessions.\u003Cbr>  my $sessh;\u003Cbr>  if ($args-&gt;{sid}) {\u003Cbr>    $sessh = $db-&gt;getHandle('session') or return;\u003Cbr>    $sessh-&gt;execute($args-&gt;{sid}) or return;\u003Cbr>  } elsif( $args-&gt;{facility} ) {\u003Cbr>    $sessh = $db-&gt;getHandle('sessions') or return;\u003Cbr>    $sessh-&gt;execute(keys %{$args-&gt;{facility}}, $args-&gt;{max}) or return;\u003Cbr>  } else {\u003Cbr>    $sessh = $db-&gt;getHandle('sessions') or return;\u003Cbr>    $sessh-&gt;execute($args-&gt;{max}) or return;\u003Cbr>  }\u003Cbr>  my $sessions = $sessh-&gt;fetchall_arrayref({});\u003Cbr>  my $nodeh = $db-&gt;getHandle('nodes') or return;\u003Cbr>  my $objh = $db-&gt;getHandle('objects') or return;\u003Cbr>  foreach my $sd (@$sessions) {\u003Cbr>\u003Cbr>    # Tweak session data.\u003Cbr>    $sd-&gt;{time} =~ tr\u002F- \u002F:-\u002F;\u003Cbr>    $sd-&gt;{endtime} =~ tr\u002F- \u002F:-\u002F if defined $sd-&gt;{endtime};\u003Cbr>    $sd-&gt;{user} = delete $sd-&gt;{username};  # user is a reserved word in SQL\u003Cbr>    $sd-&gt;{user} .= ' (SUM)' if $sd-&gt;{facility} eq 'acc_sso';\u003Cbr>    $sd-&gt;{user} = utils::Sanitize::sanitize($sd-&gt;{user}) if $sd-&gt;{user};\u003Cbr>\u003Cbr>    # Fetch node changes.\u003Cbr>    $nodeh-&gt;execute($sd-&gt;{sid}) or return;\u003Cbr>    foreach my $node (@{ $nodeh-&gt;fetchall_arrayref({}) }) {\u003Cbr>      $node-&gt;{time} =~ tr\u002F- \u002F:-\u002F;\u003Cbr>      $node-&gt;{node_descr} = Message::get_phrase(\u003Cbr>        'N', $node, { Nattrs =&gt; ['node'] });\u003Cbr>      $sd-&gt;{main}{$node-&gt;{node}} ||= [];\u003Cbr>      push @{$sd-&gt;{main}{$node-&gt;{node}}}, $node;\u003Cbr>    }\u003Cbr>    \u003Cbr>    # Fetch object changes.\u003Cbr>    $objh-&gt;execute($sd-&gt;{sid}) or return;\u003Cbr>    foreach my $object (@{ $objh-&gt;fetchall_arrayref({}) }) {\u003Cbr>      my $attrs = $object-&gt;{attrs} || [];\u003Cbr>      $object-&gt;{attributes} = [];\u003Cbr>      while (@$attrs) {\u003Cbr>        my $name = shift @$attrs;\u003Cbr>        $object-&gt;{\"attr_$name\"} = shift @$attrs;\u003Cbr>        $object-&gt;{\"oldattr_$name\"} = shift @$attrs;\u003Cbr>        $object-&gt;{\"descr_$name\"} = Message::get_phrase(\u003Cbr>          'A', $object, { attr =&gt; $name });\u003Cbr>        push @{$object-&gt;{attributes}}, $name;\u003Cbr>      }\u003Cbr>      delete $object-&gt;{attrs};\u003Cbr>      if (@{$object-&gt;{attributes}}) {\u003Cbr>        $object-&gt;{attributes} = [ sort @{$object-&gt;{attributes}} ];\u003Cbr>      } else {\u003Cbr>        delete $object-&gt;{attributes};\u003Cbr>      }\u003Cbr>      $object-&gt;{time} =~ tr\u002F- \u002F:-\u002F;\u003Cbr>      $object-&gt;{obj_descr} = Message::get_phrase('O', $object, {});\u003Cbr>      $sd-&gt;{objects}{$object-&gt;{ref}} ||= [];\u003Cbr>      push @{$sd-&gt;{objects}{$object-&gt;{ref}}}, $object;\u003Cbr>    }\u003Cbr>  }\u003Cbr>  $db-&gt;disconnect;\u003Cbr>\u003Cbr>  return $sessions;\u003Cbr>}\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Code Analysis:\u003C\u002Fp>\u003Cp>The following operations are executed from the reporting database to achieve data reading:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>sessions:   SELECT sid,facility,srcip,username,time,endtime,state FROM confd_sessions;\u003Cbr>nodes:      SELECT * FROM confd_nodes;\u003Cbr>objects:    SELECT * FROM confd_objects;\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Through testing and analysis, confd_sessions stores Session information\u003C\u002Fp>\u003Cp>CMD command to read Session information:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>psql reporting -U postgres -c 'SELECT sid,facility,srcip,username,time,endtime,state FROM confd_sessions;'\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch4>(2) File Operations\u003C\u002Fh4>\u003Cp>Key code:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>sub _iterate_files {\u003Cbr>  my ($self, $args) = @_;\u003Cbr>\u003Cbr>  # choose the first file to process\u003Cbr>  my $filename = '\u002Fvar\u002Flog\u002Fconfd.log';\u003Cbr>  if (defined $args-&gt;{time}) {\u003Cbr>    my @then;\u003Cbr>    if ($args-&gt;{time} =~ \u002F^(\\d{4}):(\\d\\d):(\\d\\d)\u002F) {\u003Cbr>      @then = (0, 0, 12, $3, $2-1, $1-1900);\u003Cbr>    } else {\u003Cbr>      @then  = localtime($args-&gt;{time});\u003Cbr>    }\u003Cbr>    my $then  = POSIX::strftime('%F', @then);\u003Cbr>    my $now   = POSIX::strftime('%F', localtime);\u003Cbr>    $filename = POSIX::strftime(\u003Cbr>      '\u002Fvar\u002Flog\u002Fconfd\u002F%Y\u002F%m\u002Fconfd-%Y-%m-%d.log.gz',\u003Cbr>      @then,\u003Cbr>    ) if $then ne $now;\u003Cbr>  }\u003Cbr>\u003Cbr>  # process the first file\u003Cbr>  my $sessions = [];\u003Cbr>  my $sdata = {};\u003Cbr>  _parse_file($self, $filename, $sessions, $sdata, $args);\u003Cbr>\u003Cbr>  # if needed, process archived log files\u003Cbr>  if (@$sessions &lt; $args-&gt;{max} &amp;&amp; not $args-&gt;{time}) {\u003Cbr>    my $iter = File::Next::files({\u003Cbr>      file_filter =&gt; sub { \u002F\\.log\\.gz$\u002F },\u003Cbr>      sort_files =&gt; \\&amp;File::Next::sort_reverse,\u003Cbr>    }, '\u002Fvar\u002Flog\u002Fconfd');\u003Cbr>    while (@$sessions &lt; $args-&gt;{max}) {\u003Cbr>      $filename = $iter-&gt;();\u003Cbr>      last unless defined $filename;\u003Cbr>      my @new_sessions;\u003Cbr>      _parse_file($self, $filename, \\@new_sessions, $sdata, $args);\u003Cbr>      push @$sessions, @new_sessions;\u003Cbr>    }\u003Cbr>  }\u003Cbr>\u003Cbr>  # limit the number of sessions to report on\u003Cbr>  splice @$sessions, $args-&gt;{max} if @$sessions &gt;= $args-&gt;{max};\u003Cbr>  return [ @{$sdata}{@$sessions} ];\u003Cbr>}\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Code Analysis:\u003C\u002Fp>\u003Cp>Read the file \u002Fvar\u002Flog\u002Fconfd.log. \u002Fvar\u002Flog\u002Fconfd.log only stores logs from the current time back to a certain period. Logs from earlier times are saved in \u002Fvar\u002Flog\u002Fconfd\u002F%Y\u002F%m\u002Fconfd-%Y-%m-%d.log.gz. For example, logs from May 16, 2022, are located at \u002Fvar\u002Flog\u002Fconfd\u002F2022\u002F05\u002Fconfd-2022-05-16.log.gz.\u003C\u002Fp>\u003Cp>Through testing and analysis, \u002Fvar\u002Flog\u002Fconfd.log stores Session information.\u003C\u002Fp>\u003Ch3>7. Edit the Session information stored in the file.\u003C\u002Fh3>\u003Cp>View successful login information:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>cat \u002Fvar\u002Flog\u002Fconfd.log | grep success\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Example of returned result:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>2022:05:23-00:19:33 test confd[41177]: I Role::authenticate:185() =&gt; id=\"3106\" severity=\"info\" sys=\"System\" sub=\"confd\" name=\"authentication successful\" user=\"admin\" srcip=\"192.168.1.2\" sid=\"8ad7bbf2781b006d99176eea9050694811e745e04acfab3dd0179620109a41ab\" facility=\"webadmin\" client=\"webadmin.plx\" call=\"new\"&lt;31&gt;May 23 00:19:33 confd[41177]: D sys::AUTOLOAD:307() =&gt; id=\"3100\" severity=\"debug\" sys=\"System\" sub=\"confd\" name=\"external call\" user=\"admin\" srcip=\"192.168.1.2\" facility=\"webadmin\" client=\"webadmin.plx\" lock=\"none\" method=\"get_SID\"\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>From the result, obtain the sid as 8ad7bbf2781b006d99176eea9050694811e745e04acfab3dd0179620109a41ab.\u003C\u002Fp>\u003Cp>Filter information for the specified sid:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>cat \u002Fvar\u002Flog\u002Fconfd.log | grep 8ad7bbf2781b006d99176eea9050694811e745e04acfab3dd0179620109a41ab\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Example of returned result:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>2022:05:23-00:19:33 test confd[41177]: I Role::authenticate:185() =&gt; id=\"3106\" severity=\"info\" sys=\"System\" sub=\"confd\" name=\"authentication successful\" user=\"admin\" srcip=\"192.168.1.2\" sid=\"8ad7bbf2781b006d99176eea9050694811e745e04acfab3dd0179620109a41ab\" facility=\"webadmin\" client=\"webadmin.plx\" call=\"new\"&lt;31&gt;May 23 00:19:33 confd[41177]: D sys::AUTOLOAD:307() =&gt; id=\"3100\" severity=\"debug\" sys=\"System\" sub=\"confd\" name=\"external call\" user=\"admin\" srcip=\"192.168.1.2\" facility=\"webadmin\" client=\"webadmin.plx\" lock=\"none\" method=\"get_SID\"\u003Cbr>2022:05:23-00:50:24 test confd[5198]: I Session::terminate:292() =&gt; id=\"3100\" severity=\"info\" sys=\"System\" sub=\"confd\" name=\"closing session\" user=\"admin\" srcip=\"192.168.1.2\" sid=\"8ad7bbf2781b006d99176eea9050694811e745e04acfab3dd0179620109a41ab\" facility=\"webadmin\" client=\"webadmin.plx\" call=\"logout\" function=\"logout\"\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Extract from it:\u003C\u002Fp>\u003Cul>\u003Cli>authentication successful: 2022:05:23-00:19:33\u003C\u002Fli>\u003Cli>User: admin\u003C\u002Fli>\u003Cli>srcip: 192.168.1.2\u003C\u002Fli>\u003Cli>closing session: 2022:05:23-00:50:24\u003C\u002Fli>\u003C\u002Ful>\u003Cp>Comparing the above information with the Last WebAdmin Sessions in the Web management page Management, it is found that the data is consistent\u003C\u002Fp>\u003Cp>Delete the above information:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>sed -i \"\u002F8ad7bbf2781b006d99176eea9050694811e745e04acfab3dd0179620109a41ab\u002Fd\" \u002Fvar\u002Flog\u002Fconfd.log\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Refreshing the Web management page Management, it is found that this method cannot clear the Last WebAdmin Sessions records\u003C\u002Fp>\u003Ch3>8. Edit the Session information stored in the database\u003C\u002Fh3>\u003Cp>Query information for the specified sid:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>psql reporting -U postgres -c \"SELECT sid,facility,srcip,username,time,endtime,state FROM confd_sessions WHERE sid ='8ad7bbf2781b006d99176eea9050694811e745e04acfab3dd0179620109a41ab';\"\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Delete information for the specified sid:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>psql reporting -U postgres -c \"DELETE FROM confd_sessions WHERE sid ='f7cce7739e98229816be6b186ada2e2942064cbf0093e329e98939fe65d8d3e3';\"\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>Refreshing the Web management page Management reveals that this method can clear the Last WebAdmin Sessions records (including Changelog)\u003C\u002Fp>\u003Ch2>0x04 Implementation Method\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>Based on the above content, the method to clear Last WebAdmin Sessions records is derived: delete the corresponding records in the reporting database\u003C\u002Fp>\u003Cp>Specific steps are as follows:\u003C\u002Fp>\u003Ch3>1. Confirm the sid corresponding to the Last WebAdmin Sessions records\u003C\u002Fh3>\u003Cp>Read the file \u002Fvar\u002Flog\u002Fconfd.log, query command:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>cat \u002Fvar\u002Flog\u002Fconfd.log| grep success\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Cp>From the returned results, confirm the sid of the Session records\u003C\u002Fp>\u003Ch3>2. Delete the Session records corresponding to the sid\u003C\u002Fh3>\u003Cp>Command example:\u003C\u002Fp>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Ctd>\u003Cp>psql reporting -U postgres -c \"DELETE FROM confd_sessions WHERE sid ='f7cce7739e98229816be6b186ada2e2942064cbf0093e329e98939fe65d8d3e3';\"\u003C\u002Fp>\u003C\u002Ftd>\u003C\u002Ftr>\u003C\u002Ftbody>\u003C\u002Ftable>\u003Ch2>0x05 Summary\u003C\u002Fh2>\u003Cp>---\u003C\u002Fp>\u003Cp>This article details the method for clearing Last WebAdmin Sessions records.\u003C\u002Fp>\u003C\u002Fbody>\u003C\u002Fhtml>",1136,"Onedaysec",8,"published","2026-02-02T07:51:00.263Z",{"title":37,"description":14,"keywords":38,"ogImage":39,"canonicalUrl":39,"noIndex":40},"Clear Sophos UTM WebAdmin Sessions Records - Technical Guide","Sophos UTM, WebAdmin sessions, clear login records, technical research, userlog_read, configuration modification",null,false,[],{"docs":43,"hasNextPage":40},[44,4,45,46],452,450,449,{"title":39,"description":39,"image":39},"2026-07-24T15:37:13.253Z","2026-07-23T16:01:36.072Z","draft","2026-07-23T16:06:24.704Z"]