[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fGdba2SUKv_EBO1qNP-8wtzrvioVNV_358iGb9B6V7Ok":3},{"id":4,"question":5,"answer":6,"answerHtml":7,"slug":8,"keywords":9,"article":10,"status":34,"aiModel":39,"aiConfidence":39,"updatedAt":51,"createdAt":52,"_status":50},449,"What is the Last WebAdmin Sessions feature in Sophos UTM and how is it accessed?","Last WebAdmin Sessions is a log feature accessible via the web management page under Management. It records each user login with details like username, login time, logout time, IP address, and configuration changes. By default, it shows the most recent 20 records. Understanding this feature is crucial for forensic analysis, similar to how administrators might [clear single records in RecentFileCache.bcf and Amcache.hve](\u002Fnews\u002Fpenetration-techniques-clearing-single-records-in-recentfilecache-bcf-and-amcache-hve) on Windows systems.","\u003Cp>Last WebAdmin Sessions is a log feature accessible via the web management page under Management. It records each user login with details like username, login time, logout time, IP address, and configuration changes. By default, it shows the most recent 20 records. Understanding this feature is crucial for forensic analysis, similar to how administrators might [clear single records in RecentFileCache.bcf and Amcache.hve](\u002Fnews\u002Fpenetration-techniques-clearing-single-records-in-recentfilecache-bcf-and-amcache-hve) on Windows systems.\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>","what-is-the-last-webadmin-sessions-feature-in-sophos-utm-and-how-is-it-accessed-1777483657653","Sophos UTM, Last WebAdmin Sessions, web management, login records",{"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,45,46,4],452,451,450,{"title":39,"description":39,"image":39},"2026-07-24T15:37:13.253Z","2026-07-23T16:01:36.072Z","draft","2026-07-23T16:06:24.058Z","2026-07-23T16:06:24.057Z"]